r1948 - in trunk/src/host/qemu-neo1973: . audio darwin-user fpu hw keymaps linux-user linux-user/alpha linux-user/i386 linux-user/mips linux-user/ppc linux-user/ppc64 linux-user/x86_64 openmoko pc-bios slirp target-alpha target-arm target-i386 target-m68k target-mips target-ppc target-sh4 target-sparc tests
andrew at sita.openmoko.org
andrew at sita.openmoko.org
Sat May 12 01:47:21 CEST 2007
Author: andrew
Date: 2007-05-12 01:44:50 +0200 (Sat, 12 May 2007)
New Revision: 1948
Added:
trunk/src/host/qemu-neo1973/arm-semi.c
trunk/src/host/qemu-neo1973/darwin-user/
trunk/src/host/qemu-neo1973/darwin-user/commpage.c
trunk/src/host/qemu-neo1973/darwin-user/ioctls.h
trunk/src/host/qemu-neo1973/darwin-user/ioctls_types.h
trunk/src/host/qemu-neo1973/darwin-user/machload.c
trunk/src/host/qemu-neo1973/darwin-user/main.c
trunk/src/host/qemu-neo1973/darwin-user/mmap.c
trunk/src/host/qemu-neo1973/darwin-user/qemu.h
trunk/src/host/qemu-neo1973/darwin-user/signal.c
trunk/src/host/qemu-neo1973/darwin-user/syscall.c
trunk/src/host/qemu-neo1973/darwin-user/syscalls.h
trunk/src/host/qemu-neo1973/hostregs_helper.h
trunk/src/host/qemu-neo1973/hw/alpha_palcode.c
trunk/src/host/qemu-neo1973/hw/ds1225y.c
trunk/src/host/qemu-neo1973/hw/eepro100.c
trunk/src/host/qemu-neo1973/hw/eeprom93xx.c
trunk/src/host/qemu-neo1973/hw/eeprom93xx.h
trunk/src/host/qemu-neo1973/hw/gt64xxx.c
trunk/src/host/qemu-neo1973/hw/i2c.c
trunk/src/host/qemu-neo1973/hw/irq.c
trunk/src/host/qemu-neo1973/hw/irq.h
trunk/src/host/qemu-neo1973/hw/mips_int.c
trunk/src/host/qemu-neo1973/hw/mips_malta.c
trunk/src/host/qemu-neo1973/hw/mips_pica61.c
trunk/src/host/qemu-neo1973/hw/pl181.c
trunk/src/host/qemu-neo1973/hw/ppc405.h
trunk/src/host/qemu-neo1973/hw/ppc405_boards.c
trunk/src/host/qemu-neo1973/hw/ppc405_uc.c
trunk/src/host/qemu-neo1973/hw/pxa2xx.c
trunk/src/host/qemu-neo1973/hw/smbus.c
trunk/src/host/qemu-neo1973/hw/smbus.h
trunk/src/host/qemu-neo1973/hw/smbus_eeprom.c
trunk/src/host/qemu-neo1973/hw/vmmouse.c
trunk/src/host/qemu-neo1973/hw/vmware_vga.c
trunk/src/host/qemu-neo1973/linux-user/alpha/
trunk/src/host/qemu-neo1973/linux-user/alpha/syscall.h
trunk/src/host/qemu-neo1973/linux-user/alpha/syscall_nr.h
trunk/src/host/qemu-neo1973/linux-user/alpha/termbits.h
trunk/src/host/qemu-neo1973/linux-user/i386/
trunk/src/host/qemu-neo1973/linux-user/i386/syscall.h
trunk/src/host/qemu-neo1973/linux-user/i386/syscall_nr.h
trunk/src/host/qemu-neo1973/linux-user/i386/termbits.h
trunk/src/host/qemu-neo1973/linux-user/ppc64/
trunk/src/host/qemu-neo1973/linux-user/ppc64/syscall.h
trunk/src/host/qemu-neo1973/linux-user/ppc64/syscall_nr.h
trunk/src/host/qemu-neo1973/linux-user/ppc64/termbits.h
trunk/src/host/qemu-neo1973/linux-user/x86_64/
trunk/src/host/qemu-neo1973/linux-user/x86_64/syscall.h
trunk/src/host/qemu-neo1973/linux-user/x86_64/syscall_nr.h
trunk/src/host/qemu-neo1973/linux-user/x86_64/termbits.h
trunk/src/host/qemu-neo1973/pc-bios/openbios-sparc64
trunk/src/host/qemu-neo1973/target-alpha/
trunk/src/host/qemu-neo1973/target-alpha/cpu.h
trunk/src/host/qemu-neo1973/target-alpha/exec.h
trunk/src/host/qemu-neo1973/target-alpha/helper.c
trunk/src/host/qemu-neo1973/target-alpha/op.c
trunk/src/host/qemu-neo1973/target-alpha/op_helper.c
trunk/src/host/qemu-neo1973/target-alpha/op_helper.h
trunk/src/host/qemu-neo1973/target-alpha/op_helper_mem.h
trunk/src/host/qemu-neo1973/target-alpha/op_mem.h
trunk/src/host/qemu-neo1973/target-alpha/op_template.h
trunk/src/host/qemu-neo1973/target-alpha/translate.c
trunk/src/host/qemu-neo1973/target-arm/op_iwmmxt.c
trunk/src/host/qemu-neo1973/target-mips/TODO
trunk/src/host/qemu-neo1973/target-mips/translate_init.c
trunk/src/host/qemu-neo1973/target-ppc/STATUS
trunk/src/host/qemu-neo1973/target-ppc/mfrom_table.c
trunk/src/host/qemu-neo1973/target-ppc/mfrom_table_gen.c
trunk/src/host/qemu-neo1973/target-ppc/op_helper.h
trunk/src/host/qemu-neo1973/uboot_image.h
trunk/src/host/qemu-neo1973/x_keymap.c
Removed:
trunk/src/host/qemu-neo1973/README.distrib
trunk/src/host/qemu-neo1973/hw/md.c
trunk/src/host/qemu-neo1973/keymaps/zaurus
trunk/src/host/qemu-neo1973/linux-2.6.9-qemu-fast.patch
trunk/src/host/qemu-neo1973/linux-user/arm-semi.c
Modified:
trunk/src/host/qemu-neo1973/Changelog
trunk/src/host/qemu-neo1973/LICENSE
trunk/src/host/qemu-neo1973/Makefile
trunk/src/host/qemu-neo1973/Makefile.target
trunk/src/host/qemu-neo1973/VERSION
trunk/src/host/qemu-neo1973/a.out.h
trunk/src/host/qemu-neo1973/audio/alsaaudio.c
trunk/src/host/qemu-neo1973/audio/audio.c
trunk/src/host/qemu-neo1973/audio/audio.h
trunk/src/host/qemu-neo1973/audio/audio_template.h
trunk/src/host/qemu-neo1973/audio/coreaudio.c
trunk/src/host/qemu-neo1973/audio/mixeng.c
trunk/src/host/qemu-neo1973/audio/mixeng.h
trunk/src/host/qemu-neo1973/audio/ossaudio.c
trunk/src/host/qemu-neo1973/audio/wavaudio.c
trunk/src/host/qemu-neo1973/audio/wavcapture.c
trunk/src/host/qemu-neo1973/block-qcow2.c
trunk/src/host/qemu-neo1973/block-raw.c
trunk/src/host/qemu-neo1973/block-vmdk.c
trunk/src/host/qemu-neo1973/block.c
trunk/src/host/qemu-neo1973/configure
trunk/src/host/qemu-neo1973/console.c
trunk/src/host/qemu-neo1973/cpu-all.h
trunk/src/host/qemu-neo1973/cpu-defs.h
trunk/src/host/qemu-neo1973/cpu-exec.c
trunk/src/host/qemu-neo1973/dis-asm.h
trunk/src/host/qemu-neo1973/disas.c
trunk/src/host/qemu-neo1973/dyngen-exec.h
trunk/src/host/qemu-neo1973/dyngen.c
trunk/src/host/qemu-neo1973/dyngen.h
trunk/src/host/qemu-neo1973/ecc.h
trunk/src/host/qemu-neo1973/elf.h
trunk/src/host/qemu-neo1973/elf_ops.h
trunk/src/host/qemu-neo1973/exec-all.h
trunk/src/host/qemu-neo1973/exec.c
trunk/src/host/qemu-neo1973/fpu/softfloat-native.c
trunk/src/host/qemu-neo1973/fpu/softfloat-native.h
trunk/src/host/qemu-neo1973/fpu/softfloat.c
trunk/src/host/qemu-neo1973/fpu/softfloat.h
trunk/src/host/qemu-neo1973/gdbstub.c
trunk/src/host/qemu-neo1973/gdbstub.h
trunk/src/host/qemu-neo1973/hw/acpi.c
trunk/src/host/qemu-neo1973/hw/adlib.c
trunk/src/host/qemu-neo1973/hw/ads7846.c
trunk/src/host/qemu-neo1973/hw/apb_pci.c
trunk/src/host/qemu-neo1973/hw/apic.c
trunk/src/host/qemu-neo1973/hw/arm_boot.c
trunk/src/host/qemu-neo1973/hw/arm_gic.c
trunk/src/host/qemu-neo1973/hw/arm_pic.c
trunk/src/host/qemu-neo1973/hw/arm_pic.h
trunk/src/host/qemu-neo1973/hw/arm_sysctl.c
trunk/src/host/qemu-neo1973/hw/arm_timer.c
trunk/src/host/qemu-neo1973/hw/cirrus_vga.c
trunk/src/host/qemu-neo1973/hw/cs4231.c
trunk/src/host/qemu-neo1973/hw/cuda.c
trunk/src/host/qemu-neo1973/hw/es1370.c
trunk/src/host/qemu-neo1973/hw/esp.c
trunk/src/host/qemu-neo1973/hw/fdc.c
trunk/src/host/qemu-neo1973/hw/grackle_pci.c
trunk/src/host/qemu-neo1973/hw/heathrow_pic.c
trunk/src/host/qemu-neo1973/hw/i2c.h
trunk/src/host/qemu-neo1973/hw/i8254.c
trunk/src/host/qemu-neo1973/hw/i8259.c
trunk/src/host/qemu-neo1973/hw/ide.c
trunk/src/host/qemu-neo1973/hw/integratorcp.c
trunk/src/host/qemu-neo1973/hw/lsi53c895a.c
trunk/src/host/qemu-neo1973/hw/m48t59.c
trunk/src/host/qemu-neo1973/hw/m48t59.h
trunk/src/host/qemu-neo1973/hw/max111x.c
trunk/src/host/qemu-neo1973/hw/max7310.c
trunk/src/host/qemu-neo1973/hw/mc146818rtc.c
trunk/src/host/qemu-neo1973/hw/mips_r4k.c
trunk/src/host/qemu-neo1973/hw/mips_timer.c
trunk/src/host/qemu-neo1973/hw/modem.c
trunk/src/host/qemu-neo1973/hw/nand.c
trunk/src/host/qemu-neo1973/hw/ne2000.c
trunk/src/host/qemu-neo1973/hw/neo1973.c
trunk/src/host/qemu-neo1973/hw/openpic.c
trunk/src/host/qemu-neo1973/hw/parallel.c
trunk/src/host/qemu-neo1973/hw/pc.c
trunk/src/host/qemu-neo1973/hw/pcf5060x.c
trunk/src/host/qemu-neo1973/hw/pci.c
trunk/src/host/qemu-neo1973/hw/pckbd.c
trunk/src/host/qemu-neo1973/hw/pcnet.c
trunk/src/host/qemu-neo1973/hw/pcspk.c
trunk/src/host/qemu-neo1973/hw/pflash_cfi02.c
trunk/src/host/qemu-neo1973/hw/piix_pci.c
trunk/src/host/qemu-neo1973/hw/pl011.c
trunk/src/host/qemu-neo1973/hw/pl050.c
trunk/src/host/qemu-neo1973/hw/pl080.c
trunk/src/host/qemu-neo1973/hw/pl110.c
trunk/src/host/qemu-neo1973/hw/pl190.c
trunk/src/host/qemu-neo1973/hw/ppc.c
trunk/src/host/qemu-neo1973/hw/ppc_chrp.c
trunk/src/host/qemu-neo1973/hw/ppc_prep.c
trunk/src/host/qemu-neo1973/hw/prep_pci.c
trunk/src/host/qemu-neo1973/hw/ps2.c
trunk/src/host/qemu-neo1973/hw/pxa.h
trunk/src/host/qemu-neo1973/hw/pxa2xx_dma.c
trunk/src/host/qemu-neo1973/hw/pxa2xx_gpio.c
trunk/src/host/qemu-neo1973/hw/pxa2xx_lcd.c
trunk/src/host/qemu-neo1973/hw/pxa2xx_mmci.c
trunk/src/host/qemu-neo1973/hw/pxa2xx_pcmcia.c
trunk/src/host/qemu-neo1973/hw/pxa2xx_pic.c
trunk/src/host/qemu-neo1973/hw/pxa2xx_timer.c
trunk/src/host/qemu-neo1973/hw/realview.c
trunk/src/host/qemu-neo1973/hw/rtl8139.c
trunk/src/host/qemu-neo1973/hw/s3c.h
trunk/src/host/qemu-neo1973/hw/s3c2410.c
trunk/src/host/qemu-neo1973/hw/s3c24xx_gpio.c
trunk/src/host/qemu-neo1973/hw/s3c24xx_lcd.c
trunk/src/host/qemu-neo1973/hw/s3c24xx_mmci.c
trunk/src/host/qemu-neo1973/hw/s3c24xx_rtc.c
trunk/src/host/qemu-neo1973/hw/s3c24xx_udc.c
trunk/src/host/qemu-neo1973/hw/sb16.c
trunk/src/host/qemu-neo1973/hw/scsi-disk.c
trunk/src/host/qemu-neo1973/hw/sd.c
trunk/src/host/qemu-neo1973/hw/sd.h
trunk/src/host/qemu-neo1973/hw/serial.c
trunk/src/host/qemu-neo1973/hw/sh7750.c
trunk/src/host/qemu-neo1973/hw/shix.c
trunk/src/host/qemu-neo1973/hw/slavio_intctl.c
trunk/src/host/qemu-neo1973/hw/slavio_misc.c
trunk/src/host/qemu-neo1973/hw/slavio_serial.c
trunk/src/host/qemu-neo1973/hw/slavio_timer.c
trunk/src/host/qemu-neo1973/hw/smc91c111.c
trunk/src/host/qemu-neo1973/hw/sparc32_dma.c
trunk/src/host/qemu-neo1973/hw/spitz.c
trunk/src/host/qemu-neo1973/hw/sun4m.c
trunk/src/host/qemu-neo1973/hw/sun4u.c
trunk/src/host/qemu-neo1973/hw/tcx.c
trunk/src/host/qemu-neo1973/hw/unin_pci.c
trunk/src/host/qemu-neo1973/hw/usb-hid.c
trunk/src/host/qemu-neo1973/hw/usb-msd.c
trunk/src/host/qemu-neo1973/hw/usb-net.c
trunk/src/host/qemu-neo1973/hw/usb-ohci.c
trunk/src/host/qemu-neo1973/hw/usb-uhci.c
trunk/src/host/qemu-neo1973/hw/usb.h
trunk/src/host/qemu-neo1973/hw/versatile_pci.c
trunk/src/host/qemu-neo1973/hw/versatilepb.c
trunk/src/host/qemu-neo1973/hw/vga.c
trunk/src/host/qemu-neo1973/hw/vga_int.h
trunk/src/host/qemu-neo1973/hw/wm8750.c
trunk/src/host/qemu-neo1973/hw/wm8753.c
trunk/src/host/qemu-neo1973/keymaps.c
trunk/src/host/qemu-neo1973/kqemu.c
trunk/src/host/qemu-neo1973/linux-user/elfload.c
trunk/src/host/qemu-neo1973/linux-user/flatload.c
trunk/src/host/qemu-neo1973/linux-user/main.c
trunk/src/host/qemu-neo1973/linux-user/mips/syscall_nr.h
trunk/src/host/qemu-neo1973/linux-user/ppc/termbits.h
trunk/src/host/qemu-neo1973/linux-user/qemu.h
trunk/src/host/qemu-neo1973/linux-user/signal.c
trunk/src/host/qemu-neo1973/linux-user/syscall.c
trunk/src/host/qemu-neo1973/linux-user/syscall_defs.h
trunk/src/host/qemu-neo1973/loader.c
trunk/src/host/qemu-neo1973/monitor.c
trunk/src/host/qemu-neo1973/openmoko/download.sh
trunk/src/host/qemu-neo1973/openmoko/flash.sh
trunk/src/host/qemu-neo1973/osdep.c
trunk/src/host/qemu-neo1973/osdep.h
trunk/src/host/qemu-neo1973/pc-bios/README
trunk/src/host/qemu-neo1973/pc-bios/bios.bin
trunk/src/host/qemu-neo1973/pc-bios/bios.diff
trunk/src/host/qemu-neo1973/pc-bios/openbios-sparc32
trunk/src/host/qemu-neo1973/ppc.ld
trunk/src/host/qemu-neo1973/qemu-binfmt-conf.sh
trunk/src/host/qemu-neo1973/qemu-doc.texi
trunk/src/host/qemu-neo1973/qemu-img.c
trunk/src/host/qemu-neo1973/qemu-tech.texi
trunk/src/host/qemu-neo1973/sdl.c
trunk/src/host/qemu-neo1973/slirp/bootp.c
trunk/src/host/qemu-neo1973/slirp/tftp.c
trunk/src/host/qemu-neo1973/slirp/tftp.h
trunk/src/host/qemu-neo1973/slirp/udp.c
trunk/src/host/qemu-neo1973/softmmu_header.h
trunk/src/host/qemu-neo1973/sparc.ld
trunk/src/host/qemu-neo1973/target-arm/cpu.h
trunk/src/host/qemu-neo1973/target-arm/exec.h
trunk/src/host/qemu-neo1973/target-arm/helper.c
trunk/src/host/qemu-neo1973/target-arm/op.c
trunk/src/host/qemu-neo1973/target-arm/translate.c
trunk/src/host/qemu-neo1973/target-i386/cpu.h
trunk/src/host/qemu-neo1973/target-i386/helper.c
trunk/src/host/qemu-neo1973/target-i386/helper2.c
trunk/src/host/qemu-neo1973/target-i386/op.c
trunk/src/host/qemu-neo1973/target-i386/ops_sse.h
trunk/src/host/qemu-neo1973/target-i386/translate.c
trunk/src/host/qemu-neo1973/target-m68k/cpu.h
trunk/src/host/qemu-neo1973/target-m68k/translate.c
trunk/src/host/qemu-neo1973/target-mips/cpu.h
trunk/src/host/qemu-neo1973/target-mips/exec.h
trunk/src/host/qemu-neo1973/target-mips/fop_template.c
trunk/src/host/qemu-neo1973/target-mips/helper.c
trunk/src/host/qemu-neo1973/target-mips/mips-defs.h
trunk/src/host/qemu-neo1973/target-mips/op.c
trunk/src/host/qemu-neo1973/target-mips/op_helper.c
trunk/src/host/qemu-neo1973/target-mips/op_helper_mem.c
trunk/src/host/qemu-neo1973/target-mips/op_mem.c
trunk/src/host/qemu-neo1973/target-mips/op_template.c
trunk/src/host/qemu-neo1973/target-mips/translate.c
trunk/src/host/qemu-neo1973/target-ppc/cpu.h
trunk/src/host/qemu-neo1973/target-ppc/exec.h
trunk/src/host/qemu-neo1973/target-ppc/helper.c
trunk/src/host/qemu-neo1973/target-ppc/op.c
trunk/src/host/qemu-neo1973/target-ppc/op_helper.c
trunk/src/host/qemu-neo1973/target-ppc/op_helper_mem.h
trunk/src/host/qemu-neo1973/target-ppc/op_mem.h
trunk/src/host/qemu-neo1973/target-ppc/op_template.h
trunk/src/host/qemu-neo1973/target-ppc/translate.c
trunk/src/host/qemu-neo1973/target-ppc/translate_init.c
trunk/src/host/qemu-neo1973/target-sh4/cpu.h
trunk/src/host/qemu-neo1973/target-sh4/helper.c
trunk/src/host/qemu-neo1973/target-sh4/op.c
trunk/src/host/qemu-neo1973/target-sh4/translate.c
trunk/src/host/qemu-neo1973/target-sparc/cpu.h
trunk/src/host/qemu-neo1973/target-sparc/exec.h
trunk/src/host/qemu-neo1973/target-sparc/op.c
trunk/src/host/qemu-neo1973/target-sparc/op_helper.c
trunk/src/host/qemu-neo1973/target-sparc/translate.c
trunk/src/host/qemu-neo1973/tests/Makefile
trunk/src/host/qemu-neo1973/tests/test-arm-iwmmxt.s
trunk/src/host/qemu-neo1973/tests/test-i386.c
trunk/src/host/qemu-neo1973/translate-all.c
trunk/src/host/qemu-neo1973/vl.c
trunk/src/host/qemu-neo1973/vl.h
trunk/src/host/qemu-neo1973/vnc.c
Log:
Merge changes from cvs.savannah.nongnu.org:/sources/qemu.
Merge Paul Brook's I2C/SMBus framework and drop our own I2C fwk.
Rewrite interrupt handling to use the new framework.
Update MMC host to use the new APIs. Update CPU selection to the new API.
Rewrite GPIO handling to use only the IRQ fwk.
Convert memory mapping to the Fabrice Bellard's new API. Convert I2C slaves and S3C2410 I2C master to new API.
Correct a ton of bugs spotted during the update. (a basic test was done but things may still be broken because the update)
Modified: trunk/src/host/qemu-neo1973/Changelog
===================================================================
--- trunk/src/host/qemu-neo1973/Changelog 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/Changelog 2007-05-11 23:44:50 UTC (rev 1948)
@@ -1,5 +1,13 @@
-version 0.8.3:
+ - TFTP booting from host directory (Anthony Liguori, Erwan Velu)
+ - Tap device emulation for Solaris (Sittichai Palanisong)
+ - Monitor multiplexing to several I/O channels (Jason Wessel)
+ - ds1225y nvram support (Herve Poussineau)
+ - CPU model selection support (J. Mayer, Paul Brook, Herve Poussineau)
+ - Several Sparc fixes (Aurelien Jarno, Blue Swirl)
+ - MIPS 64-bit FPU support (Thiemo Seufer)
+version 0.9.0:
+
- Support for relative paths in backing files for disk images
- Async file I/O API
- New qcow2 disk image format
@@ -7,6 +15,14 @@
- Linux: specific host CDROM and floppy support
- SMM support
- Moved PCI init, MP table init and ACPI table init to Bochs BIOS
+ - Support for MIPS32 Release 2 instruction set (Thiemo Seufer)
+ - MIPS Malta system emulation (Aurelien Jarno, Stefan Weil)
+ - Darwin userspace emulation (Pierre d'Herbemont)
+ - m68k user support (Paul Brook)
+ - several x86 and x86_64 emulation fixes
+ - Mouse relative offset VNC extension (Anthony Liguori)
+ - PXE boot support (Anthony Liguori)
+ - '-daemonize' option (Anthony Liguori)
version 0.8.2:
@@ -15,7 +31,7 @@
- switch to OpenBios for SPARC targets (Blue Swirl)
- VNC server fixes
- MIPS FPU support (Marius Groeger)
- - Solaris/SPARC host support (Ben Taylor)
+ - Solaris/SPARC host support (Juergen Keil)
- PPC breakpoints and single stepping (Jason Wessel)
- USB updates (Paul Brook)
- UDP/TCP/telnet character devices (Jason Wessel)
@@ -34,7 +50,7 @@
- PC speaker support (Joachim Henke)
- IDE LBA48 support (Jens Axboe)
- SSE3 support
- - Solaris port (Ben Taylor)
+ - Solaris port (Juergen Keil)
- Preliminary SH4 target (Samuel Tardieu)
- VNC server (Anthony Liguori)
- slirp fixes (Ed Swierk et al.)
Modified: trunk/src/host/qemu-neo1973/LICENSE
===================================================================
--- trunk/src/host/qemu-neo1973/LICENSE 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/LICENSE 2007-05-11 23:44:50 UTC (rev 1948)
@@ -1,12 +1,15 @@
-The following points clarify the QEMU licenses:
+The following points clarify the QEMU license:
-1) The QEMU virtual CPU core library (libqemu.a) and the QEMU PC
- system emulator are released under the GNU Lesser General Public
- License.
+1) QEMU as a whole is released under the GNU General Public License
-2) The Linux user mode QEMU emulator is released under the GNU General
- Public License.
+2) Parts of QEMU have specific licenses which are compatible with the
+GNU General Public License. Hence each source file contains its own
+licensing information.
+In particular, the QEMU virtual CPU core library (libqemu.a) is
+released under the GNU Lesser General Public License. Many hardware
+device emulation sources are released under the BSD license.
+
3) QEMU is a trademark of Fabrice Bellard.
Fabrice Bellard.
\ No newline at end of file
Modified: trunk/src/host/qemu-neo1973/Makefile
===================================================================
--- trunk/src/host/qemu-neo1973/Makefile 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/Makefile 2007-05-11 23:44:50 UTC (rev 1948)
@@ -8,10 +8,9 @@
BASE_CFLAGS=
BASE_LDFLAGS=
-BASE_CFLAGS += $(OS_CFLAGS)
-ifeq ($(ARCH),sparc)
-BASE_CFLAGS += -mcpu=ultrasparc
-endif
+BASE_CFLAGS += $(OS_CFLAGS) $(ARCH_CFLAGS)
+BASE_LDFLAGS += $(OS_LDFLAGS) $(ARCH_LDFLAGS)
+
CPPFLAGS += -I. -D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
LIBS=
TOOLS=qemu-img$(EXESUF) raw2flash$(EXESUF) flash2raw$(EXESUF)
@@ -135,7 +134,8 @@
html: qemu-doc.html qemu-tech.html
-FILE=qemu-$(shell cat VERSION)
+VERSION ?= $(shell cat VERSION)
+FILE = qemu-$(VERSION)
# tar release (use 'make -k tar' on a checkouted tree)
tar:
@@ -149,18 +149,24 @@
( cd / ; tar zcvf ~/qemu-$(VERSION)-i386.tar.gz \
$(bindir)/qemu \
$(bindir)/qemu-system-ppc \
+ $(bindir)/qemu-system-ppc64 \
+ $(bindir)/qemu-system-ppcemb \
$(bindir)/qemu-system-sparc \
$(bindir)/qemu-system-x86_64 \
$(bindir)/qemu-system-mips \
$(bindir)/qemu-system-mipsel \
+ $(bindir)/qemu-system-mips64 \
+ $(bindir)/qemu-system-mips64el \
$(bindir)/qemu-system-arm \
$(bindir)/qemu-i386 \
$(bindir)/qemu-arm \
$(bindir)/qemu-armeb \
$(bindir)/qemu-sparc \
$(bindir)/qemu-ppc \
+ $(bindir)/qemu-ppc64 \
$(bindir)/qemu-mips \
$(bindir)/qemu-mipsel \
+ $(bindir)/qemu-alpha \
$(bindir)/qemu-img \
$(datadir)/bios.bin \
$(datadir)/vgabios.bin \
@@ -169,6 +175,9 @@
$(datadir)/video.x \
$(datadir)/openbios-sparc32 \
$(datadir)/linux_boot.bin \
+ $(datadir)/pxe-ne2k_pci.bin \
+ $(datadir)/pxe-rtl8139.bin \
+ $(datadir)/pxe-pcnet.bin \
$(docdir)/qemu-doc.html \
$(docdir)/qemu-tech.html \
$(mandir)/man1/qemu.1 $(mandir)/man1/qemu-img.1 )
Modified: trunk/src/host/qemu-neo1973/Makefile.target
===================================================================
--- trunk/src/host/qemu-neo1973/Makefile.target 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/Makefile.target 2007-05-11 23:44:50 UTC (rev 1948)
@@ -4,16 +4,26 @@
ifeq ($(TARGET_ARCH), x86_64)
TARGET_BASE_ARCH:=i386
endif
+ifeq ($(TARGET_ARCH), mips64)
+TARGET_BASE_ARCH:=mips
+endif
ifeq ($(TARGET_ARCH), ppc64)
TARGET_BASE_ARCH:=ppc
endif
+ifeq ($(TARGET_ARCH), ppcemb)
+TARGET_BASE_ARCH:=ppc
+endif
ifeq ($(TARGET_ARCH), sparc64)
TARGET_BASE_ARCH:=sparc
endif
TARGET_PATH=$(SRC_PATH)/target-$(TARGET_BASE_ARCH)
VPATH=$(SRC_PATH):$(TARGET_PATH):$(SRC_PATH)/hw:$(SRC_PATH)/audio
CPPFLAGS=-I. -I.. -I$(TARGET_PATH) -I$(SRC_PATH)
-ifdef CONFIG_USER_ONLY
+ifdef CONFIG_DARWIN_USER
+VPATH+=:$(SRC_PATH)/darwin-user
+CPPFLAGS+=-I$(SRC_PATH)/darwin-user -I$(SRC_PATH)/darwin-user/$(TARGET_ARCH)
+endif
+ifdef CONFIG_LINUX_USER
VPATH+=:$(SRC_PATH)/linux-user
CPPFLAGS+=-I$(SRC_PATH)/linux-user -I$(SRC_PATH)/linux-user/$(TARGET_ARCH)
endif
@@ -40,6 +50,11 @@
TARGET_ARCH2=mipsel
endif
endif
+ifeq ($(TARGET_ARCH),mips64)
+ ifneq ($(TARGET_WORDS_BIGENDIAN),yes)
+ TARGET_ARCH2=mips64el
+ endif
+endif
QEMU_USER=qemu-$(TARGET_ARCH2)
# system emulator name
ifdef CONFIG_SOFTMMU
@@ -61,17 +76,31 @@
endif
endif # !CONFIG_USER_ONLY
+ifdef CONFIG_STATIC
+BASE_LDFLAGS+=-static
+endif
+
# We require -O2 to avoid the stack setup prologue in EXIT_TB
-OP_CFLAGS = -Wall -O2 -g -fno-strict-aliasing
+OP_CFLAGS := -Wall -O2 -g -fno-strict-aliasing
+# cc-option
+# Usage: OP_CFLAGS+=$(call cc-option, -falign-functions=0, -malign-functions=0)
+
+cc-option = $(shell if $(CC) $(OP_CFLAGS) $(1) -S -o /dev/null -xc /dev/null \
+ > /dev/null 2>&1; then echo "$(1)"; else echo "$(2)"; fi ;)
+
+OP_CFLAGS+=$(call cc-option, -fno-reorder-blocks, "")
+OP_CFLAGS+=$(call cc-option, -fno-gcse, "")
+OP_CFLAGS+=$(call cc-option, -fno-tree-ch, "")
+OP_CFLAGS+=$(call cc-option, -fno-optimize-sibling-calls, "")
+OP_CFLAGS+=$(call cc-option, -fno-crossjumping, "")
+OP_CFLAGS+=$(call cc-option, -fno-align-labels, "")
+OP_CFLAGS+=$(call cc-option, -fno-align-jumps, "")
+OP_CFLAGS+=$(call cc-option, -fno-align-functions, $(call cc-option, -malign-functions=0, ""))
+
ifeq ($(ARCH),i386)
HELPER_CFLAGS+=-fomit-frame-pointer
OP_CFLAGS+=-mpreferred-stack-boundary=2 -fomit-frame-pointer
-ifeq ($(HAVE_GCC3_OPTIONS),yes)
-OP_CFLAGS+= -falign-functions=0 -fno-gcse
-else
-OP_CFLAGS+= -malign-functions=0
-endif
ifdef TARGET_GPROF
USE_I386_LD=y
endif
@@ -81,47 +110,50 @@
ifdef USE_I386_LD
BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
else
+ifdef CONFIG_LINUX_USER
# WARNING: this LDFLAGS is _very_ tricky : qemu is an ELF shared object
# that the kernel ELF loader considers as an executable. I think this
# is the simplest way to make it self virtualizable!
BASE_LDFLAGS+=-Wl,-shared
endif
endif
+endif
ifeq ($(ARCH),x86_64)
-HELPER_CFLAGS+=-fomit-frame-pointer
BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
endif
ifeq ($(ARCH),ppc)
CPPFLAGS+= -D__powerpc__
+ifdef CONFIG_LINUX_USER
BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
endif
+endif
ifeq ($(ARCH),s390)
BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
endif
ifeq ($(ARCH),sparc)
-ifeq ($(CONFIG_SOLARIS),yes)
-BASE_CFLAGS+=-mcpu=ultrasparc -m32 -ffixed-g2 -ffixed-g3
-BASE_LDFLAGS+=-m32
-OP_CFLAGS+=-fno-delayed-branch -fno-omit-frame-pointer -ffixed-i0
-else
-BASE_CFLAGS+=-mcpu=ultrasparc -m32 -ffixed-g1 -ffixed-g2 -ffixed-g3 -ffixed-g6
-BASE_LDFLAGS+=-m32
-OP_CFLAGS+=-fno-delayed-branch -ffixed-i0
-HELPER_CFLAGS=$(CFLAGS) -ffixed-i0 -mflat
-# -static is used to avoid g1/g3 usage by the dynamic linker
-BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld -static
+ BASE_CFLAGS+=-ffixed-g2 -ffixed-g3
+ OP_CFLAGS+=-fno-delayed-branch -ffixed-i0
+ ifeq ($(CONFIG_SOLARIS),yes)
+ OP_CFLAGS+=-fno-omit-frame-pointer
+ else
+ BASE_CFLAGS+=-ffixed-g1 -ffixed-g6
+ HELPER_CFLAGS=$(CFLAGS) -ffixed-i0 -mflat
+ # -static is used to avoid g1/g3 usage by the dynamic linker
+ BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld -static
+ endif
endif
-endif
ifeq ($(ARCH),sparc64)
-BASE_CFLAGS+=-mcpu=ultrasparc -m64 -ffixed-g1 -ffixed-g4 -ffixed-g5 -ffixed-g7
-BASE_LDFLAGS+=-m64
-BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
-OP_CFLAGS+=-mcpu=ultrasparc -m64 -ffixed-g1 -ffixed-g4 -ffixed-g5 -ffixed-g7 -fno-delayed-branch -ffixed-i0
+ BASE_CFLAGS+=-ffixed-g1 -ffixed-g4 -ffixed-g5 -ffixed-g7
+ OP_CFLAGS+=-mcpu=ultrasparc -m64 -fno-delayed-branch -ffixed-i0
+ ifneq ($(CONFIG_SOLARIS),yes)
+ BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
+ OP_CFLAGS+=-ffixed-g1 -ffixed-g4 -ffixed-g5 -ffixed-g7
+ endif
endif
ifeq ($(ARCH),alpha)
@@ -149,20 +181,37 @@
endif
ifeq ($(ARCH),mips)
+OP_CFLAGS+=-mabi=32 -G0 -fno-PIC -mno-abicalls -fomit-frame-pointer -fno-delayed-branch -Wa,-O0
+ifeq ($(WORDS_BIGENDIAN),yes)
BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
+else
+BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH)el.ld
endif
+endif
-ifeq ($(HAVE_GCC3_OPTIONS),yes)
-# very important to generate a return at the end of every operation
-OP_CFLAGS+=-fno-reorder-blocks -fno-optimize-sibling-calls
+ifeq ($(ARCH),mips64)
+OP_CFLAGS+=-mabi=n32 -G0 -fno-PIC -mno-abicalls -fomit-frame-pointer -fno-delayed-branch -Wa,-O0
+ifeq ($(WORDS_BIGENDIAN),yes)
+BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
+else
+BASE_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH)el.ld
endif
+endif
ifeq ($(CONFIG_DARWIN),yes)
LIBS+=-lmx
endif
-OP_CFLAGS+=$(OS_CFLAGS)
+ifdef CONFIG_DARWIN_USER
+# Leave some space for the regular program loading zone
+BASE_LDFLAGS+=-Wl,-segaddr,__STD_PROG_ZONE,0x1000 -image_base 0x0e000000
+endif
+BASE_CFLAGS+=$(OS_CFLAGS) $(ARCH_CFLAGS)
+BASE_LDFLAGS+=$(OS_LDFLAGS) $(ARCH_LDFLAGS)
+OP_CFLAGS+=$(OS_CFLAGS) $(ARCH_CFLAGS)
+OP_LDFLAGS+=$(OS_LDFLAGS) $(ARCH_LDFLAGS)
+
#########################################################
CPPFLAGS+=-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
@@ -175,7 +224,13 @@
endif
ifdef CONFIG_SOLARIS
LIBS+=-lsocket -lnsl -lresolv
+ifdef NEEDS_LIBSUNMATH
+LIBS+=-lsunmath
+LDFLAGS+=-L/opt/SUNWspro/prod/lib -R/opt/SUNWspro/prod/lib
+OP_CFLAGS+=-I/opt/SUNWspro/prod/include/cc
+BASE_CFLAGS+=-I/opt/SUNWspro/prod/include/cc
endif
+endif
# profiling code
ifdef TARGET_GPROF
@@ -183,8 +238,10 @@
main.o: BASE_CFLAGS+=-p
endif
+ifdef CONFIG_LINUX_USER
OBJS= main.o syscall.o mmap.o signal.o path.o osdep.o thunk.o \
elfload.o linuxload.o
+LIBS+= $(AIOLIBS)
ifdef TARGET_HAS_BFLT
OBJS+= flatload.o
endif
@@ -200,6 +257,12 @@
ifeq ($(TARGET_ARCH), m68k)
OBJS+= m68k-sim.o m68k-semi.o
endif
+endif #CONFIG_LINUX_USER
+
+ifdef CONFIG_DARWIN_USER
+OBJS= main.o commpage.o machload.o mmap.o osdep.o signal.o syscall.o thunk.o
+endif
+
SRCS:= $(OBJS:.o=.c)
OBJS+= libqemu.a
@@ -228,7 +291,7 @@
LIBOBJS+= op_helper.o helper.o
endif
-ifeq ($(TARGET_ARCH), mips)
+ifeq ($(TARGET_BASE_ARCH), mips)
LIBOBJS+= op_helper.o helper.o
endif
@@ -248,6 +311,10 @@
LIBOBJS+= helper.o
endif
+ifeq ($(TARGET_BASE_ARCH), alpha)
+LIBOBJS+= op_helper.o helper.o alpha_palcode.o
+endif
+
# NOTE: the disassembler code is only needed for debugging
LIBOBJS+=disas.o
ifeq ($(findstring i386, $(TARGET_ARCH) $(ARCH)),i386)
@@ -265,7 +332,7 @@
ifeq ($(findstring ppc, $(TARGET_BASE_ARCH) $(ARCH)),ppc)
LIBOBJS+=ppc-dis.o
endif
-ifeq ($(findstring mips, $(TARGET_ARCH) $(ARCH)),mips)
+ifeq ($(findstring mips, $(TARGET_BASE_ARCH) $(ARCH)),mips)
LIBOBJS+=mips-dis.o
endif
ifeq ($(findstring sparc, $(TARGET_BASE_ARCH) $(ARCH)),sparc)
@@ -300,6 +367,7 @@
VL_OBJS+=cutils.o
VL_OBJS+=block.o block-raw.o
VL_OBJS+=block-cow.o block-qcow.o aes.o block-vmdk.o block-cloop.o block-dmg.o block-bochs.o block-vpc.o block-vvfat.o block-qcow2.o
+VL_OBJS+=irq.o
ifdef CONFIG_WIN32
VL_OBJS+=tap-win32.o
endif
@@ -333,6 +401,8 @@
endif
AUDIODRV+= wavcapture.o
+VL_OBJS += i2c.o smbus.o
+
# SCSI layer
VL_OBJS+= scsi-disk.o cdrom.o lsi53c895a.o
@@ -340,27 +410,36 @@
VL_OBJS+= usb.o usb-hub.o usb-linux.o usb-hid.o usb-ohci.o usb-msd.o usb-net.o
VL_OBJS+= usb-linux-gadget.o
+# EEPROM emulation
+VL_OBJS += eeprom93xx.o
+
# PCI network cards
-VL_OBJS+= ne2000.o rtl8139.o pcnet.o
+VL_OBJS += eepro100.o
+VL_OBJS += ne2000.o
+VL_OBJS += pcnet.o
+VL_OBJS += rtl8139.o
ifeq ($(TARGET_BASE_ARCH), i386)
# Hardware support
VL_OBJS+= ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pcspk.o pc.o
VL_OBJS+= cirrus_vga.o apic.o parallel.o acpi.o piix_pci.o
-VL_OBJS+= usb-uhci.o
+VL_OBJS+= usb-uhci.o smbus_eeprom.o vmmouse.o vmware_vga.o
CPPFLAGS += -DHAS_AUDIO -DHAS_AUDIO_CHOICE
endif
ifeq ($(TARGET_BASE_ARCH), ppc)
VL_OBJS+= ppc.o ide.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o $(AUDIODRV)
-VL_OBJS+= mc146818rtc.o serial.o i8259.o i8254.o fdc.o m48t59.o
+VL_OBJS+= mc146818rtc.o serial.o i8259.o i8254.o fdc.o m48t59.o pflash_cfi02.o
VL_OBJS+= ppc_prep.o ppc_chrp.o cuda.o adb.o openpic.o heathrow_pic.o
-VL_OBJS+= grackle_pci.o prep_pci.o unin_pci.o
+VL_OBJS+= grackle_pci.o prep_pci.o unin_pci.o ppc405_uc.o ppc405_boards.o
CPPFLAGS += -DHAS_AUDIO -DHAS_AUDIO_CHOICE
endif
-ifeq ($(TARGET_ARCH), mips)
-VL_OBJS+= mips_r4k.o mips_timer.o dma.o vga.o serial.o i8254.o i8259.o ide.o
-VL_OBJS+= mc146818rtc.o #pckbd.o fdc.o m48t59.o
+ifeq ($(TARGET_BASE_ARCH), mips)
+VL_OBJS+= mips_r4k.o mips_malta.o mips_pica61.o
+VL_OBJS+= mips_timer.o mips_int.o dma.o vga.o serial.o i8254.o i8259.o
+VL_OBJS+= ide.o gt64xxx.o pckbd.o ps2.o fdc.o mc146818rtc.o usb-uhci.o acpi.o ds1225y.o
+VL_OBJS+= piix_pci.o parallel.o mixeng.o cirrus_vga.o $(SOUND_HW) $(AUDIODRV)
+CPPFLAGS += -DHAS_AUDIO
endif
ifeq ($(TARGET_BASE_ARCH), sparc)
ifeq ($(TARGET_ARCH), sparc64)
@@ -375,12 +454,13 @@
endif
ifeq ($(TARGET_BASE_ARCH), arm)
VL_OBJS+= integratorcp.o versatilepb.o ps2.o smc91c111.o arm_pic.o arm_timer.o
-VL_OBJS+= arm_boot.o pl011.o pl050.o pl080.o pl110.o pl190.o
-VL_OBJS+= versatile_pci.o
+VL_OBJS+= arm_boot.o pl011.o pl050.o pl080.o pl110.o pl181.o pl190.o
+VL_OBJS+= versatile_pci.o sd.o
VL_OBJS+= arm_gic.o realview.o arm_sysctl.o
-VL_OBJS+= pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o spitz.o
+VL_OBJS+= arm-semi.o
+VL_OBJS+= pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o
VL_OBJS+= pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o max111x.o max7310.o
-VL_OBJS+= ads7846.o sd.o ide.o serial.o nand.o $(AUDIODRV) wm8750.o wm8753.o
+VL_OBJS+= spitz.o ads7846.o ide.o serial.o nand.o $(AUDIODRV) wm8750.o wm8753.o
VL_OBJS+= s3c2410.o s3c24xx_gpio.o s3c24xx_lcd.o s3c24xx_mmci.o s3c24xx_rtc.o
VL_OBJS+= s3c24xx_udc.o neo1973.o pcf5060x.o jbt6k74.o modem.o
CPPFLAGS += -DHAS_AUDIO
@@ -392,7 +472,7 @@
VL_OBJS+=gdbstub.o
endif
ifdef CONFIG_SDL
-VL_OBJS+=sdl.o
+VL_OBJS+=sdl.o x_keymap.o
endif
VL_OBJS+=vnc.o
ifdef CONFIG_COCOA
@@ -436,8 +516,10 @@
endif
ifeq ($(ARCH),sparc64)
-VL_LDFLAGS+=-m64
-VL_LDFLAGS+=-Wl,-T,$(SRC_PATH)/sparc64.ld
+ VL_LDFLAGS+=-m64
+ ifneq ($(CONFIG_SOLARIS),yes)
+ VL_LDFLAGS+=-Wl,-T,$(SRC_PATH)/$(ARCH).ld
+ endif
endif
ifdef CONFIG_WIN32
@@ -445,7 +527,7 @@
endif
$(QEMU_SYSTEM): $(VL_OBJS) libqemu.a
- $(CC) $(VL_LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) $(COCOA_LIBS) $(VL_LIBS)
+ $(CC) $(VL_LDFLAGS) $(LDFLAGS) -o $@ $^ $(LIBS) $(SDL_LIBS) $(COCOA_LIBS) $(VL_LIBS)
cocoa.o: cocoa.m
$(CC) $(CFLAGS) $(CPPFLAGS) $(BASE_CFLAGS) -c -o $@ $<
@@ -528,9 +610,11 @@
translate.o: translate.c translate_init.c
endif
-ifeq ($(TARGET_ARCH), mips)
-op.o: op.c op_template.c op_mem.c
-op_helper.o: op_helper_mem.c
+ifeq ($(TARGET_BASE_ARCH), mips)
+helper.o: cpu.h exec-all.h
+op.o: op_template.c fop_template.c op_mem.c exec.h
+op_helper.o: op_helper_mem.c exec.h softmmu_template.h
+translate.o: translate_init.c exec-all.h disas.h
endif
loader.o: loader.c elf_ops.h
@@ -545,6 +629,11 @@
tc58128.o: tc58128.c
endif
+ifeq ($(TARGET_BASE_ARCH), alpha)
+op.o: op.c op_template.h op_mem.h
+op_helper.o: op_helper_mem.h
+endif
+
$(OBJS) $(LIBOBJS) $(VL_OBJS): config.h ../config-host.h
%.o: %.c
Deleted: trunk/src/host/qemu-neo1973/README.distrib
===================================================================
--- trunk/src/host/qemu-neo1973/README.distrib 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/README.distrib 2007-05-11 23:44:50 UTC (rev 1948)
@@ -1,16 +0,0 @@
-Information about the various packages used to build the current qemu
-x86 binary distribution:
-
-* gcc 2.95.2 was used for the build. A glibc 2.1.3 Debian distribution
- was used to get most of the binary packages.
-
-* wine-20020411 tarball
-
- ./configure --prefix=/usr/local/wine-i386
-
- All exe and libs were stripped. Some compile time tools and the
- includes were deleted.
-
-* ldconfig was launched to build the library links:
-
- qemu-i386 /usr/gnemul/qemu-i386/bin/ldconfig-i386 -C /usr/gnemul/qemu-i386/etc/ld.so.cache
Modified: trunk/src/host/qemu-neo1973/VERSION
===================================================================
--- trunk/src/host/qemu-neo1973/VERSION 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/VERSION 2007-05-11 23:44:50 UTC (rev 1948)
@@ -1 +1 @@
-0.8.2
\ No newline at end of file
+0.9.0
\ No newline at end of file
Modified: trunk/src/host/qemu-neo1973/a.out.h
===================================================================
--- trunk/src/host/qemu-neo1973/a.out.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/a.out.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -25,9 +25,9 @@
struct external_filehdr {
short f_magic; /* magic number */
short f_nscns; /* number of sections */
- unsigned long f_timdat; /* time & date stamp */
- unsigned long f_symptr; /* file pointer to symtab */
- unsigned long f_nsyms; /* number of symtab entries */
+ host_ulong f_timdat; /* time & date stamp */
+ host_ulong f_symptr; /* file pointer to symtab */
+ host_ulong f_nsyms; /* number of symtab entries */
short f_opthdr; /* sizeof(optional hdr) */
short f_flags; /* flags */
};
@@ -72,12 +72,12 @@
{
unsigned short magic; /* type of file */
unsigned short vstamp; /* version stamp */
- unsigned long tsize; /* text size in bytes, padded to FW bdry*/
- unsigned long dsize; /* initialized data " " */
- unsigned long bsize; /* uninitialized data " " */
- unsigned long entry; /* entry pt. */
- unsigned long text_start; /* base of text used for this file */
- unsigned long data_start; /* base of data used for this file=
+ host_ulong tsize; /* text size in bytes, padded to FW bdry*/
+ host_ulong dsize; /* initialized data " " */
+ host_ulong bsize; /* uninitialized data " " */
+ host_ulong entry; /* entry pt. */
+ host_ulong text_start; /* base of text used for this file */
+ host_ulong data_start; /* base of data used for this file=
*/
}
AOUTHDR;
@@ -103,16 +103,16 @@
struct external_scnhdr {
char s_name[8]; /* section name */
- unsigned long s_paddr; /* physical address, offset
+ host_ulong s_paddr; /* physical address, offset
of last addr in scn */
- unsigned long s_vaddr; /* virtual address */
- unsigned long s_size; /* section size */
- unsigned long s_scnptr; /* file ptr to raw data for section */
- unsigned long s_relptr; /* file ptr to relocation */
- unsigned long s_lnnoptr; /* file ptr to line numbers */
+ host_ulong s_vaddr; /* virtual address */
+ host_ulong s_size; /* section size */
+ host_ulong s_scnptr; /* file ptr to raw data for section */
+ host_ulong s_relptr; /* file ptr to relocation */
+ host_ulong s_lnnoptr; /* file ptr to line numbers */
unsigned short s_nreloc; /* number of relocation entries */
unsigned short s_nlnno; /* number of line number entries*/
- unsigned long s_flags; /* flags */
+ host_ulong s_flags; /* flags */
};
#define SCNHDR struct external_scnhdr
@@ -136,8 +136,8 @@
*/
struct external_lineno {
union {
- unsigned long l_symndx; /* function name symbol index, iff l_lnno 0 */
- unsigned long l_paddr; /* (physical) address of line number */
+ host_ulong l_symndx; /* function name symbol index, iff l_lnno 0 */
+ host_ulong l_paddr; /* (physical) address of line number */
} l_addr;
unsigned short l_lnno; /* line number */
};
@@ -156,11 +156,11 @@
union {
char e_name[E_SYMNMLEN];
struct {
- unsigned long e_zeroes;
- unsigned long e_offset;
+ host_ulong e_zeroes;
+ host_ulong e_offset;
} e;
} e;
- unsigned long e_value;
+ host_ulong e_value;
unsigned short e_scnum;
unsigned short e_type;
char e_sclass[1];
@@ -174,18 +174,18 @@
union external_auxent {
struct {
- unsigned long x_tagndx; /* str, un, or enum tag indx */
+ host_ulong x_tagndx; /* str, un, or enum tag indx */
union {
struct {
unsigned short x_lnno; /* declaration line number */
unsigned short x_size; /* str/union/array size */
} x_lnsz;
- unsigned long x_fsize; /* size of function */
+ host_ulong x_fsize; /* size of function */
} x_misc;
union {
struct { /* if ISFCN, tag, or .bb */
- unsigned long x_lnnoptr;/* ptr to fcn line # */
- unsigned long x_endndx; /* entry ndx past block end */
+ host_ulong x_lnnoptr;/* ptr to fcn line # */
+ host_ulong x_endndx; /* entry ndx past block end */
} x_fcn;
struct { /* if ISARY, up to 4 dimen. */
char x_dimen[E_DIMNUM][2];
@@ -197,22 +197,22 @@
union {
char x_fname[E_FILNMLEN];
struct {
- unsigned long x_zeroes;
- unsigned long x_offset;
+ host_ulong x_zeroes;
+ host_ulong x_offset;
} x_n;
} x_file;
struct {
- unsigned long x_scnlen; /* section length */
+ host_ulong x_scnlen; /* section length */
unsigned short x_nreloc; /* # relocation entries */
unsigned short x_nlinno; /* # line numbers */
- unsigned long x_checksum; /* section COMDAT checksum */
+ host_ulong x_checksum; /* section COMDAT checksum */
unsigned short x_associated;/* COMDAT associated section index */
char x_comdat[1]; /* COMDAT selection number */
} x_scn;
struct {
- unsigned long x_tvfill; /* tv fill value */
+ host_ulong x_tvfill; /* tv fill value */
unsigned short x_tvlen; /* length of .tv */
char x_tvran[2][2]; /* tv range */
} x_tv; /* info about .tv section (in auxent of symbol .tv)) */
@@ -344,7 +344,7 @@
unsigned short e_oemid; /* OEM identifier (for e_oeminfo), 0x0 */
unsigned short e_oeminfo; /* OEM information; e_oemid specific, 0x0 */
char e_res2[10][2]; /* Reserved words, all 0x0 */
- unsigned long e_lfanew; /* File address of new exe header, 0x80 */
+ host_ulong e_lfanew; /* File address of new exe header, 0x80 */
char dos_message[16][4]; /* other stuff, always follow DOS header */
unsigned int nt_signature; /* required NT signature, 0x4550 */
@@ -352,9 +352,9 @@
unsigned short f_magic; /* magic number */
unsigned short f_nscns; /* number of sections */
- unsigned long f_timdat; /* time & date stamp */
- unsigned long f_symptr; /* file pointer to symtab */
- unsigned long f_nsyms; /* number of symtab entries */
+ host_ulong f_timdat; /* time & date stamp */
+ host_ulong f_symptr; /* file pointer to symtab */
+ host_ulong f_nsyms; /* number of symtab entries */
unsigned short f_opthdr; /* sizeof(optional hdr) */
unsigned short f_flags; /* flags */
};
@@ -370,17 +370,17 @@
{
unsigned short magic; /* type of file */
unsigned short vstamp; /* version stamp */
- unsigned long tsize; /* text size in bytes, padded to FW bdry*/
- unsigned long dsize; /* initialized data " " */
- unsigned long bsize; /* uninitialized data " " */
- unsigned long entry; /* entry pt. */
- unsigned long text_start; /* base of text used for this file */
- unsigned long data_start; /* base of all data used for this file */
+ host_ulong tsize; /* text size in bytes, padded to FW bdry*/
+ host_ulong dsize; /* initialized data " " */
+ host_ulong bsize; /* uninitialized data " " */
+ host_ulong entry; /* entry pt. */
+ host_ulong text_start; /* base of text used for this file */
+ host_ulong data_start; /* base of all data used for this file */
/* NT extra fields; see internal.h for descriptions */
- unsigned long ImageBase;
- unsigned long SectionAlignment;
- unsigned long FileAlignment;
+ host_ulong ImageBase;
+ host_ulong SectionAlignment;
+ host_ulong FileAlignment;
unsigned short MajorOperatingSystemVersion;
unsigned short MinorOperatingSystemVersion;
unsigned short MajorImageVersion;
@@ -388,17 +388,17 @@
unsigned short MajorSubsystemVersion;
unsigned short MinorSubsystemVersion;
char Reserved1[4];
- unsigned long SizeOfImage;
- unsigned long SizeOfHeaders;
- unsigned long CheckSum;
+ host_ulong SizeOfImage;
+ host_ulong SizeOfHeaders;
+ host_ulong CheckSum;
unsigned short Subsystem;
unsigned short DllCharacteristics;
- unsigned long SizeOfStackReserve;
- unsigned long SizeOfStackCommit;
- unsigned long SizeOfHeapReserve;
- unsigned long SizeOfHeapCommit;
- unsigned long LoaderFlags;
- unsigned long NumberOfRvaAndSizes;
+ host_ulong SizeOfStackReserve;
+ host_ulong SizeOfStackCommit;
+ host_ulong SizeOfHeapReserve;
+ host_ulong SizeOfHeapCommit;
+ host_ulong LoaderFlags;
+ host_ulong NumberOfRvaAndSizes;
/* IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES]; */
char DataDirectory[16][2][4]; /* 16 entries, 2 elements/entry, 4 chars */
Added: trunk/src/host/qemu-neo1973/arm-semi.c
===================================================================
--- trunk/src/host/qemu-neo1973/arm-semi.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/arm-semi.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,458 @@
+/*
+ * Arm "Angel" semihosting syscalls
+ *
+ * Copyright (c) 2005, 2007 CodeSourcery.
+ * Written by Paul Brook.
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <time.h>
+
+#include "cpu.h"
+#ifdef CONFIG_USER_ONLY
+#include "qemu.h"
+
+#define ARM_ANGEL_HEAP_SIZE (128 * 1024 * 1024)
+#else
+#include "vl.h"
+#endif
+
+#define SYS_OPEN 0x01
+#define SYS_CLOSE 0x02
+#define SYS_WRITEC 0x03
+#define SYS_WRITE0 0x04
+#define SYS_WRITE 0x05
+#define SYS_READ 0x06
+#define SYS_READC 0x07
+#define SYS_ISTTY 0x09
+#define SYS_SEEK 0x0a
+#define SYS_FLEN 0x0c
+#define SYS_TMPNAM 0x0d
+#define SYS_REMOVE 0x0e
+#define SYS_RENAME 0x0f
+#define SYS_CLOCK 0x10
+#define SYS_TIME 0x11
+#define SYS_SYSTEM 0x12
+#define SYS_ERRNO 0x13
+#define SYS_GET_CMDLINE 0x15
+#define SYS_HEAPINFO 0x16
+#define SYS_EXIT 0x18
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+#define GDB_O_RDONLY 0x000
+#define GDB_O_WRONLY 0x001
+#define GDB_O_RDWR 0x002
+#define GDB_O_APPEND 0x008
+#define GDB_O_CREAT 0x200
+#define GDB_O_TRUNC 0x400
+#define GDB_O_BINARY 0
+
+static int gdb_open_modeflags[12] = {
+ GDB_O_RDONLY,
+ GDB_O_RDONLY | GDB_O_BINARY,
+ GDB_O_RDWR,
+ GDB_O_RDWR | GDB_O_BINARY,
+ GDB_O_WRONLY | GDB_O_CREAT | GDB_O_TRUNC,
+ GDB_O_WRONLY | GDB_O_CREAT | GDB_O_TRUNC | GDB_O_BINARY,
+ GDB_O_RDWR | GDB_O_CREAT | GDB_O_TRUNC,
+ GDB_O_RDWR | GDB_O_CREAT | GDB_O_TRUNC | GDB_O_BINARY,
+ GDB_O_WRONLY | GDB_O_CREAT | GDB_O_APPEND,
+ GDB_O_WRONLY | GDB_O_CREAT | GDB_O_APPEND | GDB_O_BINARY,
+ GDB_O_RDWR | GDB_O_CREAT | GDB_O_APPEND,
+ GDB_O_RDWR | GDB_O_CREAT | GDB_O_APPEND | GDB_O_BINARY
+};
+
+static int open_modeflags[12] = {
+ O_RDONLY,
+ O_RDONLY | O_BINARY,
+ O_RDWR,
+ O_RDWR | O_BINARY,
+ O_WRONLY | O_CREAT | O_TRUNC,
+ O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
+ O_RDWR | O_CREAT | O_TRUNC,
+ O_RDWR | O_CREAT | O_TRUNC | O_BINARY,
+ O_WRONLY | O_CREAT | O_APPEND,
+ O_WRONLY | O_CREAT | O_APPEND | O_BINARY,
+ O_RDWR | O_CREAT | O_APPEND,
+ O_RDWR | O_CREAT | O_APPEND | O_BINARY
+};
+
+#ifdef CONFIG_USER_ONLY
+static inline uint32_t set_swi_errno(TaskState *ts, uint32_t code)
+{
+ if (code == (uint32_t)-1)
+ ts->swi_errno = errno;
+ return code;
+}
+#else
+static inline uint32_t set_swi_errno(CPUState *env, uint32_t code)
+{
+ return code;
+}
+
+static uint32_t softmmu_tget32(CPUState *env, uint32_t addr)
+{
+ uint32_t val;
+
+ cpu_memory_rw_debug(env, addr, (uint8_t *)&val, 4, 0);
+ return tswap32(val);
+}
+static uint32_t softmmu_tget8(CPUState *env, uint32_t addr)
+{
+ uint8_t val;
+
+ cpu_memory_rw_debug(env, addr, &val, 1, 0);
+ return val;
+}
+#define tget32(p) softmmu_tget32(env, p)
+#define tget8(p) softmmu_tget8(env, p)
+
+static void *softmmu_lock_user(CPUState *env, uint32_t addr, uint32_t len,
+ int copy)
+{
+ char *p;
+ /* TODO: Make this something that isn't fixed size. */
+ p = malloc(len);
+ if (copy)
+ cpu_memory_rw_debug(env, addr, p, len, 0);
+ return p;
+}
+#define lock_user(p, len, copy) softmmu_lock_user(env, p, len, copy)
+static char *softmmu_lock_user_string(CPUState *env, uint32_t addr)
+{
+ char *p;
+ char *s;
+ uint8_t c;
+ /* TODO: Make this something that isn't fixed size. */
+ s = p = malloc(1024);
+ do {
+ cpu_memory_rw_debug(env, addr, &c, 1, 0);
+ addr++;
+ *(p++) = c;
+ } while (c);
+ return s;
+}
+#define lock_user_string(p) softmmu_lock_user_string(env, p)
+static void softmmu_unlock_user(CPUState *env, void *p, target_ulong addr,
+ target_ulong len)
+{
+ if (len)
+ cpu_memory_rw_debug(env, addr, p, len, 1);
+ free(p);
+}
+#define unlock_user(s, args, len) softmmu_unlock_user(env, s, args, len)
+#endif
+
+static target_ulong arm_semi_syscall_len;
+
+static void arm_semi_cb(CPUState *env, target_ulong ret, target_ulong err)
+{
+#ifdef CONFIG_USER_ONLY
+ TaskState *ts = env->opaque;
+#endif
+ if (ret == (target_ulong)-1) {
+#ifdef CONFIG_USER_ONLY
+ ts->swi_errno = err;
+#endif
+ env->regs[0] = ret;
+ } else {
+ /* Fixup syscalls that use nonstardard return conventions. */
+ switch (env->regs[0]) {
+ case SYS_WRITE:
+ case SYS_READ:
+ env->regs[0] = arm_semi_syscall_len - ret;
+ break;
+ case SYS_SEEK:
+ env->regs[0] = 0;
+ break;
+ default:
+ env->regs[0] = ret;
+ break;
+ }
+ }
+}
+
+#define ARG(n) tget32(args + (n) * 4)
+#define SET_ARG(n, val) tput32(args + (n) * 4,val)
+uint32_t do_arm_semihosting(CPUState *env)
+{
+ target_ulong args;
+ char * s;
+ int nr;
+ uint32_t ret;
+ uint32_t len;
+#ifdef CONFIG_USER_ONLY
+ TaskState *ts = env->opaque;
+#else
+ CPUState *ts = env;
+#endif
+
+ nr = env->regs[0];
+ args = env->regs[1];
+ switch (nr) {
+ case SYS_OPEN:
+ s = lock_user_string(ARG(0));
+ if (ARG(1) >= 12)
+ return (uint32_t)-1;
+ if (strcmp(s, ":tt") == 0) {
+ if (ARG(1) < 4)
+ return STDIN_FILENO;
+ else
+ return STDOUT_FILENO;
+ }
+ if (use_gdb_syscalls()) {
+ gdb_do_syscall(arm_semi_cb, "open,%s,%x,1a4", ARG(0), (int)ARG(2),
+ gdb_open_modeflags[ARG(1)]);
+ return env->regs[0];
+ } else {
+ ret = set_swi_errno(ts, open(s, open_modeflags[ARG(1)], 0644));
+ }
+ unlock_user(s, ARG(0), 0);
+ return ret;
+ case SYS_CLOSE:
+ if (use_gdb_syscalls()) {
+ gdb_do_syscall(arm_semi_cb, "close,%x", ARG(0));
+ return env->regs[0];
+ } else {
+ return set_swi_errno(ts, close(ARG(0)));
+ }
+ case SYS_WRITEC:
+ {
+ char c = tget8(args);
+ /* Write to debug console. stderr is near enough. */
+ if (use_gdb_syscalls()) {
+ gdb_do_syscall(arm_semi_cb, "write,2,%x,1", args);
+ return env->regs[0];
+ } else {
+ return write(STDERR_FILENO, &c, 1);
+ }
+ }
+ case SYS_WRITE0:
+ s = lock_user_string(args);
+ len = strlen(s);
+ if (use_gdb_syscalls()) {
+ gdb_do_syscall(arm_semi_cb, "write,2,%x,%x\n", args, len);
+ ret = env->regs[0];
+ } else {
+ ret = write(STDERR_FILENO, s, len);
+ }
+ unlock_user(s, args, 0);
+ return ret;
+ case SYS_WRITE:
+ len = ARG(2);
+ if (use_gdb_syscalls()) {
+ arm_semi_syscall_len = len;
+ gdb_do_syscall(arm_semi_cb, "write,%x,%x,%x", ARG(0), ARG(1), len);
+ return env->regs[0];
+ } else {
+ s = lock_user(ARG(1), len, 1);
+ ret = set_swi_errno(ts, write(ARG(0), s, len));
+ unlock_user(s, ARG(1), 0);
+ if (ret == (uint32_t)-1)
+ return -1;
+ return len - ret;
+ }
+ case SYS_READ:
+ len = ARG(2);
+ if (use_gdb_syscalls()) {
+ arm_semi_syscall_len = len;
+ gdb_do_syscall(arm_semi_cb, "read,%x,%x,%x", ARG(0), ARG(1), len);
+ return env->regs[0];
+ } else {
+ s = lock_user(ARG(1), len, 0);
+ do
+ ret = set_swi_errno(ts, read(ARG(0), s, len));
+ while (ret == -1 && errno == EINTR);
+ unlock_user(s, ARG(1), len);
+ if (ret == (uint32_t)-1)
+ return -1;
+ return len - ret;
+ }
+ case SYS_READC:
+ /* XXX: Read from debug cosole. Not implemented. */
+ return 0;
+ case SYS_ISTTY:
+ if (use_gdb_syscalls()) {
+ gdb_do_syscall(arm_semi_cb, "isatty,%x", ARG(0));
+ return env->regs[0];
+ } else {
+ return isatty(ARG(0));
+ }
+ case SYS_SEEK:
+ if (use_gdb_syscalls()) {
+ gdb_do_syscall(arm_semi_cb, "fseek,%x,%x,0", ARG(0), ARG(1));
+ return env->regs[0];
+ } else {
+ ret = set_swi_errno(ts, lseek(ARG(0), ARG(1), SEEK_SET));
+ if (ret == (uint32_t)-1)
+ return -1;
+ return 0;
+ }
+ case SYS_FLEN:
+ if (use_gdb_syscalls()) {
+ /* TODO: Use stat syscall. */
+ return -1;
+ } else {
+ struct stat buf;
+ ret = set_swi_errno(ts, fstat(ARG(0), &buf));
+ if (ret == (uint32_t)-1)
+ return -1;
+ return buf.st_size;
+ }
+ case SYS_TMPNAM:
+ /* XXX: Not implemented. */
+ return -1;
+ case SYS_REMOVE:
+ if (use_gdb_syscalls()) {
+ gdb_do_syscall(arm_semi_cb, "unlink,%s", ARG(0), (int)ARG(1));
+ ret = env->regs[0];
+ } else {
+ s = lock_user_string(ARG(0));
+ ret = set_swi_errno(ts, remove(s));
+ unlock_user(s, ARG(0), 0);
+ }
+ return ret;
+ case SYS_RENAME:
+ if (use_gdb_syscalls()) {
+ gdb_do_syscall(arm_semi_cb, "rename,%s,%s",
+ ARG(0), (int)ARG(1), ARG(2), (int)ARG(3));
+ return env->regs[0];
+ } else {
+ char *s2;
+ s = lock_user_string(ARG(0));
+ s2 = lock_user_string(ARG(2));
+ ret = set_swi_errno(ts, rename(s, s2));
+ unlock_user(s2, ARG(2), 0);
+ unlock_user(s, ARG(0), 0);
+ return ret;
+ }
+ case SYS_CLOCK:
+ return clock() / (CLOCKS_PER_SEC / 100);
+ case SYS_TIME:
+ return set_swi_errno(ts, time(NULL));
+ case SYS_SYSTEM:
+ if (use_gdb_syscalls()) {
+ gdb_do_syscall(arm_semi_cb, "system,%s", ARG(0), (int)ARG(1));
+ return env->regs[0];
+ } else {
+ s = lock_user_string(ARG(0));
+ ret = set_swi_errno(ts, system(s));
+ unlock_user(s, ARG(0), 0);
+ }
+ case SYS_ERRNO:
+#ifdef CONFIG_USER_ONLY
+ return ts->swi_errno;
+#else
+ return 0;
+#endif
+ case SYS_GET_CMDLINE:
+#ifdef CONFIG_USER_ONLY
+ /* Build a commandline from the original argv. */
+ {
+ char **arg = ts->info->host_argv;
+ int len = ARG(1);
+ /* lock the buffer on the ARM side */
+ char *cmdline_buffer = (char*)lock_user(ARG(0), len, 0);
+
+ s = cmdline_buffer;
+ while (*arg && len > 2) {
+ int n = strlen(*arg);
+
+ if (s != cmdline_buffer) {
+ *(s++) = ' ';
+ len--;
+ }
+ if (n >= len)
+ n = len - 1;
+ memcpy(s, *arg, n);
+ s += n;
+ len -= n;
+ arg++;
+ }
+ /* Null terminate the string. */
+ *s = 0;
+ len = s - cmdline_buffer;
+
+ /* Unlock the buffer on the ARM side. */
+ unlock_user(cmdline_buffer, ARG(0), len);
+
+ /* Adjust the commandline length argument. */
+ SET_ARG(1, len);
+
+ /* Return success if commandline fit into buffer. */
+ return *arg ? -1 : 0;
+ }
+#else
+ return -1;
+#endif
+ case SYS_HEAPINFO:
+ {
+ uint32_t *ptr;
+ uint32_t limit;
+
+#ifdef CONFIG_USER_ONLY
+ /* Some C libraries assume the heap immediately follows .bss, so
+ allocate it using sbrk. */
+ if (!ts->heap_limit) {
+ long ret;
+
+ ts->heap_base = do_brk(0);
+ limit = ts->heap_base + ARM_ANGEL_HEAP_SIZE;
+ /* Try a big heap, and reduce the size if that fails. */
+ for (;;) {
+ ret = do_brk(limit);
+ if (ret != -1)
+ break;
+ limit = (ts->heap_base >> 1) + (limit >> 1);
+ }
+ ts->heap_limit = limit;
+ }
+
+ ptr = lock_user(ARG(0), 16, 0);
+ ptr[0] = tswap32(ts->heap_base);
+ ptr[1] = tswap32(ts->heap_limit);
+ ptr[2] = tswap32(ts->stack_base);
+ ptr[3] = tswap32(0); /* Stack limit. */
+ unlock_user(ptr, ARG(0), 16);
+#else
+ limit = ram_size;
+ ptr = lock_user(ARG(0), 16, 0);
+ /* TODO: Make this use the limit of the loaded application. */
+ ptr[0] = tswap32(limit / 2);
+ ptr[1] = tswap32(limit);
+ ptr[2] = tswap32(limit); /* Stack base */
+ ptr[3] = tswap32(0); /* Stack limit. */
+ unlock_user(ptr, ARG(0), 16);
+#endif
+ return 0;
+ }
+ case SYS_EXIT:
+ exit(0);
+ default:
+ fprintf(stderr, "qemu: Unsupported SemiHosting SWI 0x%02x\n", nr);
+ cpu_dump_state(env, stderr, fprintf, 0);
+ abort();
+ }
+}
Modified: trunk/src/host/qemu-neo1973/audio/alsaaudio.c
===================================================================
--- trunk/src/host/qemu-neo1973/audio/alsaaudio.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/audio/alsaaudio.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -157,6 +157,12 @@
case AUD_FMT_U16:
return SND_PCM_FORMAT_U16_LE;
+ case AUD_FMT_S32:
+ return SND_PCM_FORMAT_S32_LE;
+
+ case AUD_FMT_U32:
+ return SND_PCM_FORMAT_U32_LE;
+
default:
dolog ("Internal logic error: Bad audio format %d\n", fmt);
#ifdef DEBUG_AUDIO
@@ -199,6 +205,26 @@
*fmt = AUD_FMT_U16;
break;
+ case SND_PCM_FORMAT_S32_LE:
+ *endianness = 0;
+ *fmt = AUD_FMT_S32;
+ break;
+
+ case SND_PCM_FORMAT_U32_LE:
+ *endianness = 0;
+ *fmt = AUD_FMT_U32;
+ break;
+
+ case SND_PCM_FORMAT_S32_BE:
+ *endianness = 1;
+ *fmt = AUD_FMT_S32;
+ break;
+
+ case SND_PCM_FORMAT_U32_BE:
+ *endianness = 1;
+ *fmt = AUD_FMT_U32;
+ break;
+
default:
dolog ("Unrecognized audio format %d\n", alsafmt);
return -1;
Modified: trunk/src/host/qemu-neo1973/audio/audio.c
===================================================================
--- trunk/src/host/qemu-neo1973/audio/audio.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/audio/audio.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -80,7 +80,8 @@
{
44100, /* freq */
2, /* nchannels */
- AUD_FMT_S16 /* fmt */
+ AUD_FMT_S16, /* fmt */
+ AUDIO_HOST_ENDIANNESS
}
},
@@ -91,7 +92,8 @@
{
44100, /* freq */
2, /* nchannels */
- AUD_FMT_S16 /* fmt */
+ AUD_FMT_S16, /* fmt */
+ AUDIO_HOST_ENDIANNESS
}
},
@@ -166,6 +168,25 @@
}
#endif
+static inline int audio_bits_to_index (int bits)
+{
+ switch (bits) {
+ case 8:
+ return 0;
+
+ case 16:
+ return 1;
+
+ case 32:
+ return 2;
+
+ default:
+ audio_bug ("bits_to_index", 1);
+ AUD_log (NULL, "invalid bits %d\n", bits);
+ return 0;
+ }
+}
+
void *audio_calloc (const char *funcname, int nmemb, size_t size)
{
int cond;
@@ -227,6 +248,12 @@
case AUD_FMT_S16:
return "S16";
+
+ case AUD_FMT_U32:
+ return "U32";
+
+ case AUD_FMT_S32:
+ return "S32";
}
dolog ("Bogus audfmt %d returning S16\n", fmt);
@@ -243,6 +270,10 @@
*defaultp = 0;
return AUD_FMT_U16;
}
+ else if (!strcasecmp (s, "u32")) {
+ *defaultp = 0;
+ return AUD_FMT_U32;
+ }
else if (!strcasecmp (s, "s8")) {
*defaultp = 0;
return AUD_FMT_S8;
@@ -251,6 +282,10 @@
*defaultp = 0;
return AUD_FMT_S16;
}
+ else if (!strcasecmp (s, "s32")) {
+ *defaultp = 0;
+ return AUD_FMT_S32;
+ }
else {
dolog ("Bogus audio format `%s' using %s\n",
s, audio_audfmt_to_string (defval));
@@ -538,6 +573,8 @@
case AUD_FMT_U8:
case AUD_FMT_S16:
case AUD_FMT_U16:
+ case AUD_FMT_S32:
+ case AUD_FMT_U32:
break;
default:
invalid = 1;
@@ -563,6 +600,12 @@
case AUD_FMT_U16:
bits = 16;
break;
+
+ case AUD_FMT_S32:
+ sign = 1;
+ case AUD_FMT_U32:
+ bits = 32;
+ break;
}
return info->freq == as->freq
&& info->nchannels == as->nchannels
@@ -573,7 +616,7 @@
void audio_pcm_init_info (struct audio_pcm_info *info, audsettings_t *as)
{
- int bits = 8, sign = 0;
+ int bits = 8, sign = 0, shift = 0;
switch (as->fmt) {
case AUD_FMT_S8:
@@ -585,14 +628,22 @@
sign = 1;
case AUD_FMT_U16:
bits = 16;
+ shift = 1;
break;
+
+ case AUD_FMT_S32:
+ sign = 1;
+ case AUD_FMT_U32:
+ bits = 32;
+ shift = 2;
+ break;
}
info->freq = as->freq;
info->bits = bits;
info->sign = sign;
info->nchannels = as->nchannels;
- info->shift = (as->nchannels == 2) + (bits == 16);
+ info->shift = (as->nchannels == 2) + shift;
info->align = (1 << info->shift) - 1;
info->bytes_per_second = info->freq << info->shift;
info->swap_endianness = (as->endianness != AUDIO_HOST_ENDIANNESS);
@@ -608,22 +659,49 @@
memset (buf, 0x00, len << info->shift);
}
else {
- if (info->bits == 8) {
+ switch (info->bits) {
+ case 8:
memset (buf, 0x80, len << info->shift);
- }
- else {
- int i;
- uint16_t *p = buf;
- int shift = info->nchannels - 1;
- short s = INT16_MAX;
+ break;
- if (info->swap_endianness) {
- s = bswap16 (s);
+ case 16:
+ {
+ int i;
+ uint16_t *p = buf;
+ int shift = info->nchannels - 1;
+ short s = INT16_MAX;
+
+ if (info->swap_endianness) {
+ s = bswap16 (s);
+ }
+
+ for (i = 0; i < len << shift; i++) {
+ p[i] = s;
+ }
}
+ break;
- for (i = 0; i < len << shift; i++) {
- p[i] = s;
+ case 32:
+ {
+ int i;
+ uint32_t *p = buf;
+ int shift = info->nchannels - 1;
+ int32_t s = INT32_MAX;
+
+ if (info->swap_endianness) {
+ s = bswap32 (s);
+ }
+
+ for (i = 0; i < len << shift; i++) {
+ p[i] = s;
+ }
}
+ break;
+
+ default:
+ AUD_log (NULL, "audio_pcm_info_clear_buf: invalid bits %d\n",
+ info->bits);
+ break;
}
}
}
@@ -1811,7 +1889,7 @@
[hw->info.nchannels == 2]
[hw->info.sign]
[hw->info.swap_endianness]
- [hw->info.bits == 16];
+ [audio_bits_to_index (hw->info.bits)];
LIST_INSERT_HEAD (&s->cap_head, cap, entries);
LIST_INSERT_HEAD (&cap->cb_head, cb, entries);
Modified: trunk/src/host/qemu-neo1973/audio/audio.h
===================================================================
--- trunk/src/host/qemu-neo1973/audio/audio.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/audio/audio.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -33,7 +33,9 @@
AUD_FMT_U8,
AUD_FMT_S8,
AUD_FMT_U16,
- AUD_FMT_S16
+ AUD_FMT_S16,
+ AUD_FMT_U32,
+ AUD_FMT_S32
} audfmt_e;
#ifdef WORDS_BIGENDIAN
Modified: trunk/src/host/qemu-neo1973/audio/audio_template.h
===================================================================
--- trunk/src/host/qemu-neo1973/audio/audio_template.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/audio/audio_template.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -164,7 +164,7 @@
[sw->info.nchannels == 2]
[sw->info.sign]
[sw->info.swap_endianness]
- [sw->info.bits == 16];
+ [audio_bits_to_index (sw->info.bits)];
sw->name = qemu_strdup (name);
err = glue (audio_pcm_sw_alloc_resources_, TYPE) (sw);
@@ -288,7 +288,7 @@
[hw->info.nchannels == 2]
[hw->info.sign]
[hw->info.swap_endianness]
- [hw->info.bits == 16];
+ [audio_bits_to_index (hw->info.bits)];
if (glue (audio_pcm_hw_alloc_resources_, TYPE) (hw)) {
goto err1;
Modified: trunk/src/host/qemu-neo1973/audio/coreaudio.c
===================================================================
--- trunk/src/host/qemu-neo1973/audio/coreaudio.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/audio/coreaudio.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -294,7 +294,6 @@
coreaudioVoiceOut *core = (coreaudioVoiceOut *) hw;
UInt32 propertySize;
int err;
- int bits = 8;
const char *typ = "playback";
AudioValueRange frameRange;
@@ -305,10 +304,6 @@
return -1;
}
- if (as->fmt == AUD_FMT_S16 || as->fmt == AUD_FMT_U16) {
- bits = 16;
- }
-
audio_pcm_init_info (&hw->info, as);
/* open default output device */
Modified: trunk/src/host/qemu-neo1973/audio/mixeng.c
===================================================================
--- trunk/src/host/qemu-neo1973/audio/mixeng.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/audio/mixeng.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -82,6 +82,7 @@
#undef IN_T
#undef SHIFT
+/* Unsigned 16 bit */
#define IN_T uint16_t
#define IN_MIN 0
#define IN_MAX USHRT_MAX
@@ -101,26 +102,72 @@
#undef IN_T
#undef SHIFT
-t_sample *mixeng_conv[2][2][2][2] = {
+/* Signed 32 bit */
+#define IN_T int32_t
+#define IN_MIN INT32_MIN
+#define IN_MAX INT32_MAX
+#define SIGNED
+#define SHIFT 32
+#define ENDIAN_CONVERSION natural
+#define ENDIAN_CONVERT(v) (v)
+#include "mixeng_template.h"
+#undef ENDIAN_CONVERT
+#undef ENDIAN_CONVERSION
+#define ENDIAN_CONVERSION swap
+#define ENDIAN_CONVERT(v) bswap32 (v)
+#include "mixeng_template.h"
+#undef ENDIAN_CONVERT
+#undef ENDIAN_CONVERSION
+#undef SIGNED
+#undef IN_MAX
+#undef IN_MIN
+#undef IN_T
+#undef SHIFT
+
+/* Unsigned 16 bit */
+#define IN_T uint32_t
+#define IN_MIN 0
+#define IN_MAX UINT32_MAX
+#define SHIFT 32
+#define ENDIAN_CONVERSION natural
+#define ENDIAN_CONVERT(v) (v)
+#include "mixeng_template.h"
+#undef ENDIAN_CONVERT
+#undef ENDIAN_CONVERSION
+#define ENDIAN_CONVERSION swap
+#define ENDIAN_CONVERT(v) bswap32 (v)
+#include "mixeng_template.h"
+#undef ENDIAN_CONVERT
+#undef ENDIAN_CONVERSION
+#undef IN_MAX
+#undef IN_MIN
+#undef IN_T
+#undef SHIFT
+
+t_sample *mixeng_conv[2][2][2][3] = {
{
{
{
conv_natural_uint8_t_to_mono,
- conv_natural_uint16_t_to_mono
+ conv_natural_uint16_t_to_mono,
+ conv_natural_uint32_t_to_mono
},
{
conv_natural_uint8_t_to_mono,
- conv_swap_uint16_t_to_mono
+ conv_swap_uint16_t_to_mono,
+ conv_swap_uint32_t_to_mono,
}
},
{
{
conv_natural_int8_t_to_mono,
- conv_natural_int16_t_to_mono
+ conv_natural_int16_t_to_mono,
+ conv_natural_int32_t_to_mono
},
{
conv_natural_int8_t_to_mono,
- conv_swap_int16_t_to_mono
+ conv_swap_int16_t_to_mono,
+ conv_swap_int32_t_to_mono
}
}
},
@@ -128,46 +175,54 @@
{
{
conv_natural_uint8_t_to_stereo,
- conv_natural_uint16_t_to_stereo
+ conv_natural_uint16_t_to_stereo,
+ conv_natural_uint32_t_to_stereo
},
{
conv_natural_uint8_t_to_stereo,
- conv_swap_uint16_t_to_stereo
+ conv_swap_uint16_t_to_stereo,
+ conv_swap_uint32_t_to_stereo
}
},
{
{
conv_natural_int8_t_to_stereo,
- conv_natural_int16_t_to_stereo
+ conv_natural_int16_t_to_stereo,
+ conv_natural_int32_t_to_stereo
},
{
conv_natural_int8_t_to_stereo,
- conv_swap_int16_t_to_stereo
+ conv_swap_int16_t_to_stereo,
+ conv_swap_int32_t_to_stereo,
}
}
}
};
-f_sample *mixeng_clip[2][2][2][2] = {
+f_sample *mixeng_clip[2][2][2][3] = {
{
{
{
clip_natural_uint8_t_from_mono,
- clip_natural_uint16_t_from_mono
+ clip_natural_uint16_t_from_mono,
+ clip_natural_uint32_t_from_mono
},
{
clip_natural_uint8_t_from_mono,
- clip_swap_uint16_t_from_mono
+ clip_swap_uint16_t_from_mono,
+ clip_swap_uint32_t_from_mono
}
},
{
{
clip_natural_int8_t_from_mono,
- clip_natural_int16_t_from_mono
+ clip_natural_int16_t_from_mono,
+ clip_natural_int32_t_from_mono
},
{
clip_natural_int8_t_from_mono,
- clip_swap_int16_t_from_mono
+ clip_swap_int16_t_from_mono,
+ clip_swap_int32_t_from_mono
}
}
},
@@ -175,21 +230,25 @@
{
{
clip_natural_uint8_t_from_stereo,
- clip_natural_uint16_t_from_stereo
+ clip_natural_uint16_t_from_stereo,
+ clip_natural_uint32_t_from_stereo
},
{
clip_natural_uint8_t_from_stereo,
- clip_swap_uint16_t_from_stereo
+ clip_swap_uint16_t_from_stereo,
+ clip_swap_uint32_t_from_stereo
}
},
{
{
clip_natural_int8_t_from_stereo,
- clip_natural_int16_t_from_stereo
+ clip_natural_int16_t_from_stereo,
+ clip_natural_int32_t_from_stereo
},
{
clip_natural_int8_t_from_stereo,
- clip_swap_int16_t_from_stereo
+ clip_swap_int16_t_from_stereo,
+ clip_swap_int32_t_from_stereo
}
}
}
Modified: trunk/src/host/qemu-neo1973/audio/mixeng.h
===================================================================
--- trunk/src/host/qemu-neo1973/audio/mixeng.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/audio/mixeng.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -37,8 +37,8 @@
int samples, volume_t *vol);
typedef void (f_sample) (void *dst, const st_sample_t *src, int samples);
-extern t_sample *mixeng_conv[2][2][2][2];
-extern f_sample *mixeng_clip[2][2][2][2];
+extern t_sample *mixeng_conv[2][2][2][3];
+extern f_sample *mixeng_clip[2][2][2][3];
void *st_rate_start (int inrate, int outrate);
void st_rate_flow (void *opaque, st_sample_t *ibuf, st_sample_t *obuf,
Modified: trunk/src/host/qemu-neo1973/audio/ossaudio.c
===================================================================
--- trunk/src/host/qemu-neo1973/audio/ossaudio.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/audio/ossaudio.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -21,10 +21,15 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
+#include <stdlib.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/ioctl.h>
+#ifdef __OpenBSD__
+#include <soundcard.h>
+#else
#include <sys/soundcard.h>
+#endif
#include "vl.h"
#define AUDIO_CAP "oss"
Modified: trunk/src/host/qemu-neo1973/audio/wavaudio.c
===================================================================
--- trunk/src/host/qemu-neo1973/audio/wavaudio.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/audio/wavaudio.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -41,7 +41,8 @@
{
44100,
2,
- AUD_FMT_S16
+ AUD_FMT_S16,
+ AUDIO_HOST_ENDIANNESS
},
"qemu.wav"
};
@@ -131,6 +132,11 @@
case AUD_FMT_U16:
bits16 = 1;
break;
+
+ case AUD_FMT_S32:
+ case AUD_FMT_U32:
+ dolog ("WAVE files can not handle 32bit formats\n");
+ return -1;
}
hdr[34] = bits16 ? 0x10 : 0x08;
Modified: trunk/src/host/qemu-neo1973/audio/wavcapture.c
===================================================================
--- trunk/src/host/qemu-neo1973/audio/wavcapture.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/audio/wavcapture.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -37,15 +37,15 @@
if (wav->f) {
le_store (rlen, rifflen, 4);
le_store (dlen, datalen, 4);
-
+
qemu_fseek (wav->f, 4, SEEK_SET);
qemu_put_buffer (wav->f, rlen, 4);
-
+
qemu_fseek (wav->f, 32, SEEK_CUR);
qemu_put_buffer (wav->f, dlen, 4);
qemu_fclose (wav->f);
}
-
+
qemu_free (wav->path);
}
Modified: trunk/src/host/qemu-neo1973/block-qcow2.c
===================================================================
--- trunk/src/host/qemu-neo1973/block-qcow2.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/block-qcow2.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -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);
Modified: trunk/src/host/qemu-neo1973/block-raw.c
===================================================================
--- trunk/src/host/qemu-neo1973/block-raw.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/block-raw.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -914,8 +914,13 @@
s->hfile = CreateFile(filename, access_flags,
FILE_SHARE_READ, NULL,
create_flags, overlapped, NULL);
- if (s->hfile == INVALID_HANDLE_VALUE)
+ if (s->hfile == INVALID_HANDLE_VALUE) {
+ int err = GetLastError();
+
+ if (err == ERROR_ACCESS_DENIED)
+ return -EACCES;
return -1;
+ }
return 0;
}
@@ -1278,8 +1283,13 @@
s->hfile = CreateFile(filename, access_flags,
FILE_SHARE_READ, NULL,
create_flags, overlapped, NULL);
- if (s->hfile == INVALID_HANDLE_VALUE)
+ if (s->hfile == INVALID_HANDLE_VALUE) {
+ int err = GetLastError();
+
+ if (err == ERROR_ACCESS_DENIED)
+ return -EACCES;
return -1;
+ }
return 0;
}
Modified: trunk/src/host/qemu-neo1973/block-vmdk.c
===================================================================
--- trunk/src/host/qemu-neo1973/block-vmdk.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/block-vmdk.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -22,6 +22,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
+
#include "vl.h"
#include "block_int.h"
@@ -59,7 +60,7 @@
#define L2_CACHE_SIZE 16
typedef struct BDRVVmdkState {
- int fd;
+ BlockDriverState *hd;
int64_t l1_table_offset;
int64_t l1_backup_table_offset;
uint32_t *l1_table;
@@ -73,6 +74,7 @@
uint32_t l2_cache_counts[L2_CACHE_SIZE];
unsigned int cluster_sectors;
+ uint32_t parent_cid;
} BDRVVmdkState;
static int vmdk_probe(const uint8_t *buf, int buf_size, const char *filename)
@@ -89,27 +91,278 @@
return 0;
}
+#define CHECK_CID 1
+
+#define SECTOR_SIZE 512
+#define DESC_SIZE 20*SECTOR_SIZE // 20 sectors of 512 bytes each
+#define HEADER_SIZE 512 // first sector of 512 bytes
+
+static uint32_t vmdk_read_cid(BlockDriverState *bs, int parent)
+{
+ BDRVVmdkState *s = bs->opaque;
+ char desc[DESC_SIZE];
+ uint32_t cid;
+ char *p_name, *cid_str;
+ size_t cid_str_size;
+
+ /* the descriptor offset = 0x200 */
+ if (bdrv_pread(s->hd, 0x200, desc, DESC_SIZE) != DESC_SIZE)
+ return 0;
+
+ if (parent) {
+ cid_str = "parentCID";
+ cid_str_size = sizeof("parentCID");
+ } else {
+ cid_str = "CID";
+ cid_str_size = sizeof("CID");
+ }
+
+ if ((p_name = strstr(desc,cid_str)) != 0) {
+ p_name += cid_str_size;
+ sscanf(p_name,"%x",&cid);
+ }
+
+ return cid;
+}
+
+static int vmdk_write_cid(BlockDriverState *bs, uint32_t cid)
+{
+ BDRVVmdkState *s = bs->opaque;
+ char desc[DESC_SIZE], tmp_desc[DESC_SIZE];
+ char *p_name, *tmp_str;
+
+ /* the descriptor offset = 0x200 */
+ if (bdrv_pread(s->hd, 0x200, desc, DESC_SIZE) != DESC_SIZE)
+ return -1;
+
+ tmp_str = strstr(desc,"parentCID");
+ strcpy(tmp_desc, tmp_str);
+ if ((p_name = strstr(desc,"CID")) != 0) {
+ p_name += sizeof("CID");
+ sprintf(p_name,"%x\n",cid);
+ strcat(desc,tmp_desc);
+ }
+
+ if (bdrv_pwrite(s->hd, 0x200, desc, DESC_SIZE) != DESC_SIZE)
+ return -1;
+ return 0;
+}
+
+static int vmdk_is_cid_valid(BlockDriverState *bs)
+{
+#ifdef CHECK_CID
+ BDRVVmdkState *s = bs->opaque;
+ BlockDriverState *p_bs = s->hd->backing_hd;
+ uint32_t cur_pcid;
+
+ if (p_bs) {
+ cur_pcid = vmdk_read_cid(p_bs,0);
+ if (s->parent_cid != cur_pcid)
+ // CID not valid
+ return 0;
+ }
+#endif
+ // CID valid
+ return 1;
+}
+
+static int vmdk_snapshot_create(const char *filename, const char *backing_file)
+{
+ int snp_fd, p_fd;
+ uint32_t p_cid;
+ char *p_name, *gd_buf, *rgd_buf;
+ const char *real_filename, *temp_str;
+ VMDK4Header header;
+ uint32_t gde_entries, gd_size;
+ int64_t gd_offset, rgd_offset, capacity, gt_size;
+ char p_desc[DESC_SIZE], s_desc[DESC_SIZE], hdr[HEADER_SIZE];
+ char *desc_template =
+ "# Disk DescriptorFile\n"
+ "version=1\n"
+ "CID=%x\n"
+ "parentCID=%x\n"
+ "createType=\"monolithicSparse\"\n"
+ "parentFileNameHint=\"%s\"\n"
+ "\n"
+ "# Extent description\n"
+ "RW %lu SPARSE \"%s\"\n"
+ "\n"
+ "# The Disk Data Base \n"
+ "#DDB\n"
+ "\n";
+
+ snp_fd = open(filename, O_RDWR | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE, 0644);
+ if (snp_fd < 0)
+ return -1;
+ p_fd = open(backing_file, O_RDONLY | O_BINARY | O_LARGEFILE);
+ if (p_fd < 0) {
+ close(snp_fd);
+ return -1;
+ }
+
+ /* read the header */
+ if (lseek(p_fd, 0x0, SEEK_SET) == -1)
+ goto fail;
+ if (read(p_fd, hdr, HEADER_SIZE) != HEADER_SIZE)
+ goto fail;
+
+ /* write the header */
+ if (lseek(snp_fd, 0x0, SEEK_SET) == -1)
+ goto fail;
+ if (write(snp_fd, hdr, HEADER_SIZE) == -1)
+ goto fail;
+
+ memset(&header, 0, sizeof(header));
+ memcpy(&header,&hdr[4], sizeof(header)); // skip the VMDK4_MAGIC
+
+ ftruncate(snp_fd, header.grain_offset << 9);
+ /* the descriptor offset = 0x200 */
+ if (lseek(p_fd, 0x200, SEEK_SET) == -1)
+ goto fail;
+ if (read(p_fd, p_desc, DESC_SIZE) != DESC_SIZE)
+ goto fail;
+
+ if ((p_name = strstr(p_desc,"CID")) != 0) {
+ p_name += sizeof("CID");
+ sscanf(p_name,"%x",&p_cid);
+ }
+
+ real_filename = filename;
+ if ((temp_str = strrchr(real_filename, '\\')) != NULL)
+ real_filename = temp_str + 1;
+ if ((temp_str = strrchr(real_filename, '/')) != NULL)
+ real_filename = temp_str + 1;
+ if ((temp_str = strrchr(real_filename, ':')) != NULL)
+ real_filename = temp_str + 1;
+
+ sprintf(s_desc, desc_template, p_cid, p_cid, backing_file
+ , (uint32_t)header.capacity, real_filename);
+
+ /* write the descriptor */
+ if (lseek(snp_fd, 0x200, SEEK_SET) == -1)
+ goto fail;
+ if (write(snp_fd, s_desc, strlen(s_desc)) == -1)
+ goto fail;
+
+ gd_offset = header.gd_offset * SECTOR_SIZE; // offset of GD table
+ rgd_offset = header.rgd_offset * SECTOR_SIZE; // offset of RGD table
+ capacity = header.capacity * SECTOR_SIZE; // Extent size
+ /*
+ * Each GDE span 32M disk, means:
+ * 512 GTE per GT, each GTE points to grain
+ */
+ gt_size = (int64_t)header.num_gtes_per_gte * header.granularity * SECTOR_SIZE;
+ if (!gt_size)
+ goto fail;
+ gde_entries = (uint32_t)(capacity / gt_size); // number of gde/rgde
+ gd_size = gde_entries * sizeof(uint32_t);
+
+ /* write RGD */
+ rgd_buf = qemu_malloc(gd_size);
+ if (!rgd_buf)
+ goto fail;
+ if (lseek(p_fd, rgd_offset, SEEK_SET) == -1)
+ goto fail_rgd;
+ if (read(p_fd, rgd_buf, gd_size) != gd_size)
+ goto fail_rgd;
+ if (lseek(snp_fd, rgd_offset, SEEK_SET) == -1)
+ goto fail_rgd;
+ if (write(snp_fd, rgd_buf, gd_size) == -1)
+ goto fail_rgd;
+ qemu_free(rgd_buf);
+
+ /* write GD */
+ gd_buf = qemu_malloc(gd_size);
+ if (!gd_buf)
+ goto fail_rgd;
+ if (lseek(p_fd, gd_offset, SEEK_SET) == -1)
+ goto fail_gd;
+ if (read(p_fd, gd_buf, gd_size) != gd_size)
+ goto fail_gd;
+ if (lseek(snp_fd, gd_offset, SEEK_SET) == -1)
+ goto fail_gd;
+ if (write(snp_fd, gd_buf, gd_size) == -1)
+ goto fail_gd;
+ qemu_free(gd_buf);
+
+ close(p_fd);
+ close(snp_fd);
+ return 0;
+
+ fail_gd:
+ qemu_free(gd_buf);
+ fail_rgd:
+ qemu_free(rgd_buf);
+ fail:
+ close(p_fd);
+ close(snp_fd);
+ return -1;
+}
+
+static void vmdk_parent_close(BlockDriverState *bs)
+{
+ if (bs->backing_hd)
+ bdrv_close(bs->backing_hd);
+}
+
+
+static int vmdk_parent_open(BlockDriverState *bs, const char * filename)
+{
+ BDRVVmdkState *s = bs->opaque;
+ char *p_name;
+ char desc[DESC_SIZE];
+ char parent_img_name[1024];
+
+ /* the descriptor offset = 0x200 */
+ if (bdrv_pread(s->hd, 0x200, desc, DESC_SIZE) != DESC_SIZE)
+ return -1;
+
+ if ((p_name = strstr(desc,"parentFileNameHint")) != 0) {
+ char *end_name;
+ struct stat file_buf;
+
+ p_name += sizeof("parentFileNameHint") + 1;
+ if ((end_name = strchr(p_name,'\"')) == 0)
+ return -1;
+
+ strncpy(s->hd->backing_file, p_name, end_name - p_name);
+ if (stat(s->hd->backing_file, &file_buf) != 0) {
+ path_combine(parent_img_name, sizeof(parent_img_name),
+ filename, s->hd->backing_file);
+ } else {
+ strcpy(parent_img_name, s->hd->backing_file);
+ }
+
+ s->hd->backing_hd = bdrv_new("");
+ if (!s->hd->backing_hd) {
+ failure:
+ bdrv_close(s->hd);
+ return -1;
+ }
+ if (bdrv_open(s->hd->backing_hd, parent_img_name, 0) < 0)
+ goto failure;
+ }
+
+ return 0;
+}
+
static int vmdk_open(BlockDriverState *bs, const char *filename, int flags)
{
BDRVVmdkState *s = bs->opaque;
- int fd, i;
uint32_t magic;
- int l1_size;
+ int l1_size, i, ret;
- fd = open(filename, O_RDWR | O_BINARY | O_LARGEFILE);
- if (fd < 0) {
- fd = open(filename, O_RDONLY | O_BINARY | O_LARGEFILE);
- if (fd < 0)
- return -1;
- bs->read_only = 1;
- }
- if (read(fd, &magic, sizeof(magic)) != sizeof(magic))
+ ret = bdrv_file_open(&s->hd, filename, flags);
+ if (ret < 0)
+ return ret;
+ if (bdrv_pread(s->hd, 0, &magic, sizeof(magic)) != sizeof(magic))
goto fail;
+
magic = be32_to_cpu(magic);
if (magic == VMDK3_MAGIC) {
VMDK3Header header;
- if (read(fd, &header, sizeof(header)) !=
- sizeof(header))
+
+ if (bdrv_pread(s->hd, sizeof(magic), &header, sizeof(header)) != sizeof(header))
goto fail;
s->cluster_sectors = le32_to_cpu(header.granularity);
s->l2_size = 1 << 9;
@@ -120,8 +373,8 @@
s->l1_entry_sectors = s->l2_size * s->cluster_sectors;
} else if (magic == VMDK4_MAGIC) {
VMDK4Header header;
-
- if (read(fd, &header, sizeof(header)) != sizeof(header))
+
+ if (bdrv_pread(s->hd, sizeof(magic), &header, sizeof(header)) != sizeof(header))
goto fail;
bs->total_sectors = le64_to_cpu(header.capacity);
s->cluster_sectors = le64_to_cpu(header.granularity);
@@ -133,18 +386,23 @@
/ s->l1_entry_sectors;
s->l1_table_offset = le64_to_cpu(header.rgd_offset) << 9;
s->l1_backup_table_offset = le64_to_cpu(header.gd_offset) << 9;
+
+ // try to open parent images, if exist
+ if (vmdk_parent_open(bs, filename) != 0)
+ goto fail;
+ // write the CID once after the image creation
+ s->parent_cid = vmdk_read_cid(bs,1);
} else {
goto fail;
}
+
/* read the L1 table */
l1_size = s->l1_size * sizeof(uint32_t);
s->l1_table = qemu_malloc(l1_size);
if (!s->l1_table)
goto fail;
- if (lseek(fd, s->l1_table_offset, SEEK_SET) == -1)
+ if (bdrv_pread(s->hd, s->l1_table_offset, s->l1_table, l1_size) != l1_size)
goto fail;
- if (read(fd, s->l1_table, l1_size) != l1_size)
- goto fail;
for(i = 0; i < s->l1_size; i++) {
le32_to_cpus(&s->l1_table[i]);
}
@@ -153,10 +411,8 @@
s->l1_backup_table = qemu_malloc(l1_size);
if (!s->l1_backup_table)
goto fail;
- if (lseek(fd, s->l1_backup_table_offset, SEEK_SET) == -1)
+ if (bdrv_pread(s->hd, s->l1_backup_table_offset, s->l1_backup_table, l1_size) != l1_size)
goto fail;
- if (read(fd, s->l1_backup_table, l1_size) != l1_size)
- goto fail;
for(i = 0; i < s->l1_size; i++) {
le32_to_cpus(&s->l1_backup_table[i]);
}
@@ -165,16 +421,43 @@
s->l2_cache = qemu_malloc(s->l2_size * L2_CACHE_SIZE * sizeof(uint32_t));
if (!s->l2_cache)
goto fail;
- s->fd = fd;
return 0;
fail:
qemu_free(s->l1_backup_table);
qemu_free(s->l1_table);
qemu_free(s->l2_cache);
- close(fd);
+ bdrv_delete(s->hd);
return -1;
}
+static uint64_t get_cluster_offset(BlockDriverState *bs, uint64_t offset, int allocate);
+
+static int get_whole_cluster(BlockDriverState *bs, uint64_t cluster_offset,
+ uint64_t offset, int allocate)
+{
+ uint64_t parent_cluster_offset;
+ BDRVVmdkState *s = bs->opaque;
+ uint8_t whole_grain[s->cluster_sectors*512]; // 128 sectors * 512 bytes each = grain size 64KB
+
+ // we will be here if it's first write on non-exist grain(cluster).
+ // try to read from parent image, if exist
+ if (s->hd->backing_hd) {
+ BDRVVmdkState *ps = s->hd->backing_hd->opaque;
+
+ if (!vmdk_is_cid_valid(bs))
+ return -1;
+ parent_cluster_offset = get_cluster_offset(s->hd->backing_hd, offset, allocate);
+ if (bdrv_pread(ps->hd, parent_cluster_offset, whole_grain, ps->cluster_sectors*512) !=
+ ps->cluster_sectors*512)
+ return -1;
+
+ if (bdrv_pwrite(s->hd, cluster_offset << 9, whole_grain, sizeof(whole_grain)) !=
+ sizeof(whole_grain))
+ return -1;
+ }
+ return 0;
+}
+
static uint64_t get_cluster_offset(BlockDriverState *bs,
uint64_t offset, int allocate)
{
@@ -212,34 +495,41 @@
}
}
l2_table = s->l2_cache + (min_index * s->l2_size);
- lseek(s->fd, (int64_t)l2_offset * 512, SEEK_SET);
- if (read(s->fd, l2_table, s->l2_size * sizeof(uint32_t)) !=
- s->l2_size * sizeof(uint32_t))
+ if (bdrv_pread(s->hd, (int64_t)l2_offset * 512, l2_table, s->l2_size * sizeof(uint32_t)) !=
+ s->l2_size * sizeof(uint32_t))
return 0;
+
s->l2_cache_offsets[min_index] = l2_offset;
s->l2_cache_counts[min_index] = 1;
found:
l2_index = ((offset >> 9) / s->cluster_sectors) % s->l2_size;
cluster_offset = le32_to_cpu(l2_table[l2_index]);
if (!cluster_offset) {
+ struct stat file_buf;
+
if (!allocate)
return 0;
- cluster_offset = lseek(s->fd, 0, SEEK_END);
- ftruncate(s->fd, cluster_offset + (s->cluster_sectors << 9));
+ stat(s->hd->filename, &file_buf);
+ cluster_offset = file_buf.st_size;
+ bdrv_truncate(s->hd, cluster_offset + (s->cluster_sectors << 9));
+
cluster_offset >>= 9;
/* update L2 table */
tmp = cpu_to_le32(cluster_offset);
l2_table[l2_index] = tmp;
- lseek(s->fd, ((int64_t)l2_offset * 512) + (l2_index * sizeof(tmp)), SEEK_SET);
- if (write(s->fd, &tmp, sizeof(tmp)) != sizeof(tmp))
+ if (bdrv_pwrite(s->hd, ((int64_t)l2_offset * 512) + (l2_index * sizeof(tmp)),
+ &tmp, sizeof(tmp)) != sizeof(tmp))
return 0;
/* update backup L2 table */
if (s->l1_backup_table_offset != 0) {
l2_offset = s->l1_backup_table[l1_index];
- lseek(s->fd, ((int64_t)l2_offset * 512) + (l2_index * sizeof(tmp)), SEEK_SET);
- if (write(s->fd, &tmp, sizeof(tmp)) != sizeof(tmp))
+ if (bdrv_pwrite(s->hd, ((int64_t)l2_offset * 512) + (l2_index * sizeof(tmp)),
+ &tmp, sizeof(tmp)) != sizeof(tmp))
return 0;
}
+
+ if (get_whole_cluster(bs, cluster_offset, offset, allocate) == -1)
+ return 0;
}
cluster_offset <<= 9;
return cluster_offset;
@@ -265,9 +555,9 @@
uint8_t *buf, int nb_sectors)
{
BDRVVmdkState *s = bs->opaque;
- int ret, index_in_cluster, n;
+ int index_in_cluster, n, ret;
uint64_t cluster_offset;
-
+
while (nb_sectors > 0) {
cluster_offset = get_cluster_offset(bs, sector_num << 9, 0);
index_in_cluster = sector_num % s->cluster_sectors;
@@ -275,11 +565,18 @@
if (n > nb_sectors)
n = nb_sectors;
if (!cluster_offset) {
- memset(buf, 0, 512 * n);
+ // try to read from parent image, if exist
+ if (s->hd->backing_hd) {
+ if (!vmdk_is_cid_valid(bs))
+ return -1;
+ ret = bdrv_read(s->hd->backing_hd, sector_num, buf, n);
+ if (ret < 0)
+ return -1;
+ } else {
+ memset(buf, 0, 512 * n);
+ }
} else {
- lseek(s->fd, cluster_offset + index_in_cluster * 512, SEEK_SET);
- ret = read(s->fd, buf, n * 512);
- if (ret != n * 512)
+ if(bdrv_pread(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512) != n * 512)
return -1;
}
nb_sectors -= n;
@@ -293,8 +590,9 @@
const uint8_t *buf, int nb_sectors)
{
BDRVVmdkState *s = bs->opaque;
- int ret, index_in_cluster, n;
+ int index_in_cluster, n;
uint64_t cluster_offset;
+ static int cid_update = 0;
while (nb_sectors > 0) {
index_in_cluster = sector_num & (s->cluster_sectors - 1);
@@ -304,13 +602,17 @@
cluster_offset = get_cluster_offset(bs, sector_num << 9, 1);
if (!cluster_offset)
return -1;
- lseek(s->fd, cluster_offset + index_in_cluster * 512, SEEK_SET);
- ret = write(s->fd, buf, n * 512);
- if (ret != n * 512)
+ if (bdrv_pwrite(s->hd, cluster_offset + index_in_cluster * 512, buf, n * 512) != n * 512)
return -1;
nb_sectors -= n;
sector_num += n;
buf += n * 512;
+
+ // update CID on the first write every time the virtual disk is opened
+ if (!cid_update) {
+ vmdk_write_cid(bs, time(NULL));
+ cid_update++;
+ }
}
return 0;
}
@@ -334,7 +636,7 @@
"# The Disk Data Base \n"
"#DDB\n"
"\n"
- "ddb.virtualHWVersion = \"3\"\n"
+ "ddb.virtualHWVersion = \"4\"\n"
"ddb.geometry.cylinders = \"%lu\"\n"
"ddb.geometry.heads = \"16\"\n"
"ddb.geometry.sectors = \"63\"\n"
@@ -343,6 +645,9 @@
const char *real_filename, *temp_str;
/* XXX: add support for backing file */
+ if (backing_file) {
+ return vmdk_snapshot_create(filename, backing_file);
+ }
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_LARGEFILE,
0644);
@@ -421,15 +726,18 @@
static void vmdk_close(BlockDriverState *bs)
{
BDRVVmdkState *s = bs->opaque;
+
qemu_free(s->l1_table);
qemu_free(s->l2_cache);
- close(s->fd);
+ bdrv_delete(s->hd);
+ // try to close parent image, if exist
+ vmdk_parent_close(s->hd);
}
static void vmdk_flush(BlockDriverState *bs)
{
BDRVVmdkState *s = bs->opaque;
- fsync(s->fd);
+ bdrv_flush(s->hd);
}
BlockDriver bdrv_vmdk = {
Modified: trunk/src/host/qemu-neo1973/block.c
===================================================================
--- trunk/src/host/qemu-neo1973/block.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/block.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -322,8 +322,8 @@
BlockDriver *drv)
{
int ret, open_flags;
- char tmp_filename[1024];
- char backing_filename[1024];
+ char tmp_filename[PATH_MAX];
+ char backing_filename[PATH_MAX];
bs->read_only = 0;
bs->is_temporary = 0;
Modified: trunk/src/host/qemu-neo1973/configure
===================================================================
--- trunk/src/host/qemu-neo1973/configure 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/configure 2007-05-11 23:44:50 UTC (rev 1948)
@@ -50,10 +50,13 @@
mips)
cpu="mips"
;;
+ mips64)
+ cpu="mips64"
+ ;;
s390)
cpu="s390"
;;
- sparc|sun4[muv])
+ sparc|sun4[cdmuv])
cpu="sparc"
;;
sparc64)
@@ -94,7 +97,8 @@
check_gfx="yes"
check_gcc="yes"
softmmu="yes"
-user="no"
+linux_user="no"
+darwin_user="no"
build_docs="no"
gadgetfs="no"
uname_release=""
@@ -127,15 +131,38 @@
Darwin)
bsd="yes"
darwin="yes"
+darwin_user="yes"
+cocoa="yes"
+coreaudio="yes"
OS_CFLAGS="-mdynamic-no-pic"
;;
SunOS)
-solaris="yes"
+ solaris="yes"
+ make="gmake"
+ install="ginstall"
+ needs_libsunmath="no"
+ solarisrev=`uname -r | cut -f2 -d.`
+ if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then
+ if test "$solarisrev" -le 9 ; then
+ if test -f /opt/SUNWspro/prod/lib/libsunmath.so.1; then
+ needs_libsunmath="yes"
+ else
+ echo "QEMU will not link correctly on Solaris 8/X86 or 9/x86 without"
+ echo "libsunmath from the Sun Studio compilers tools, due to a lack of"
+ echo "C99 math features in libm.so in Solaris 8/x86 and Solaris 9/x86"
+ echo "Studio 11 can be downloaded from www.sun.com."
+ exit 1
+ fi
+ fi
+ if test "$solarisrev" -ge 9 ; then
+ kqemu="yes"
+ fi
+ fi
;;
*)
oss="yes"
linux="yes"
-user="yes"
+linux_user="yes"
if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then
kqemu="yes"
fi
@@ -148,18 +175,6 @@
fi
fi
-if [ "$solaris" = "yes" ] ; then
- make="gmake"
- install="ginstall"
- solarisrev=`uname -r | cut -f2 -d.`
-fi
-
-if [ "$bsd" = "yes" -o "$solaris" = "yes" -o "$mingw32" = "yes" ] ; then
- AIOLIBS=
-else
- AIOLIBS="-lrt"
-fi
-
# find source path
source_path=`dirname "$0"`
if [ -z "$source_path" ]; then
@@ -222,7 +237,7 @@
;;
--fmod-inc=*) fmod_inc="$optarg"
;;
- --enable-mingw32) mingw32="yes" ; cross_prefix="i386-mingw32-" ; user="no"
+ --enable-mingw32) mingw32="yes" ; cross_prefix="i386-mingw32-" ; linux_user="no"
;;
--disable-slirp) slirp="no"
;;
@@ -242,19 +257,64 @@
;;
--enable-system) softmmu="yes"
;;
- --disable-user) user="no"
+ --disable-linux-user) linux_user="no"
;;
- --enable-user) user="yes"
+ --enable-linux-user) linux_user="yes"
;;
+ --disable-darwin-user) darwin_user="no"
+ ;;
+ --enable-darwin-user) darwin_user="yes"
+ ;;
--enable-uname-release=*) uname_release="$optarg"
;;
+ --sparc_cpu=*)
+ sparc_cpu="$optarg"
+ case $sparc_cpu in
+ v7|v8) SP_CFLAGS="-m32 -mcpu=${sparc_cpu} -D__sparc_${sparc_cpu}__"; SP_LDFLAGS="-m32"
+ target_cpu="sparc"; cpu="sparc" ;;
+ v8plus|v8plusa) SP_CFLAGS="-m32 -mcpu=ultrasparc -D__sparc_${sparc_cpu}__"; SP_LDFLAGS="-m32"
+ target_cpu="sparc"; cpu="sparc" ;;
+ v9) SP_CFLAGS="-m64 -mcpu=ultrasparc -D__sparc_${sparc_cpu}__"; SP_LDFLAGS="-m64"
+ target_cpu="sparc64"; cpu="sparc64" ;;
+ *) echo "undefined SPARC architecture. Exiting";exit 1;;
+ esac
+ ;;
esac
done
+if [ "$bsd" = "yes" -o "$darwin" = "yes" -o "$mingw32" = "yes" ] ; then
+ AIOLIBS=
+else
+ AIOLIBS="-lrt"
+fi
+
# default flags for all hosts
CFLAGS="$CFLAGS -Wall -O2 -g -fno-strict-aliasing"
LDFLAGS="$LDFLAGS -g"
+#
+# If cpu ~= sparc and sparc_cpu hasn't been defined, plug in the right
+# ARCH_CFLAGS/ARCH_LDFLAGS (assume sparc_v8plus for 32-bit and sparc_v9 for 64-bit)
+#
+case $cpu in
+ sparc) if test -z "$sparc_cpu" ; then
+ ARCH_CFLAGS="-m32 -mcpu=ultrasparc -D__sparc_v8plus__"
+ ARCH_LDFLAGS="-m32"
+ else
+ ARCH_CFLAGS="${SP_CFLAGS}"
+ ARCH_LDFLAGS="${SP_LDFLAGS}"
+ fi
+ ;;
+ sparc64) if test -z "$sparc_cpu" ; then
+ ARCH_CFLAGS="-m64 -mcpu=ultrasparc -D__sparc_v9__"
+ ARCH_LDFLAGS="-m64"
+ else
+ ARCH_CFLAGS="${SP_CFLAGS}"
+ ARCH_LDFLAGS="${SP_LDFLAGS}"
+ fi
+ ;;
+esac
+
if test x"$show_help" = x"yes" ; then
cat << EOF
@@ -286,14 +346,17 @@
echo " --enable-coreaudio enable Coreaudio audio driver"
echo " --enable-alsa enable ALSA audio driver"
echo " --enable-fmod enable FMOD audio driver"
-echo " --enabled-dsound enable DirectSound audio driver"
+echo " --enable-dsound enable DirectSound audio driver"
echo " --enable-system enable all system emulation targets"
echo " --disable-system disable all system emulation targets"
-echo " --enable-user enable all linux usermode emulation targets"
-echo " --disable-user disable all linux usermode emulation targets"
+echo " --enable-linux-user enable all linux usermode emulation targets"
+echo " --disable-linux-user disable all linux usermode emulation targets"
+echo " --enable-darwin-user enable all darwin usermode emulation targets"
+echo " --disable-darwin-user disable all darwin usermode emulation targets"
echo " --fmod-lib path to FMOD library"
echo " --fmod-inc path to FMOD includes"
echo " --enable-uname-release=R Return R for uname -r in usermode emulation"
+echo " --sparc_cpu=V Build qemu for Sparc architecture v7, v8, v8plus, v8plusa, v9"
echo ""
echo "NOTE: The object files are built at the place where configure is launched"
exit 1
@@ -308,7 +371,7 @@
int main(void) {}
EOF
-if $cc -c -o $TMPO $TMPC 2>/dev/null ; then
+if $cc -c -o $TMPO $TMPC 2> /dev/null ; then
: C compiler works ok
else
echo "ERROR: \"$cc\" either does not exist or does not work"
@@ -332,20 +395,15 @@
#endif
int main(){return 0;}
EOF
- check_cc() {
- which "$1" >&/dev/null
- return $?
- }
-
- if "$cc" -o $TMPE $TMPC 2>/dev/null ; then
+ if "$cc" -o $TMPE $TMPC 2> /dev/null ; then
echo "WARNING: \"$cc\" looks like gcc 4.x"
found_compat_cc="no"
if test "$gcc3_search" = "yes" ; then
echo "Looking for gcc 3.x"
for compat_cc in $gcc3_list ; do
- if check_cc "$compat_cc" ; then
+ if "$cross_prefix$compat_cc" --version > /dev/null 2>&1 ; then
echo "Found \"$compat_cc\""
- cc="$compat_cc"
+ cc="$cross_prefix$compat_cc"
found_compat_cc="yes"
break
fi
@@ -407,12 +465,16 @@
if test -z "$target_list" ; then
# these targets are portable
if [ "$softmmu" = "yes" ] ; then
- target_list="i386-softmmu ppc-softmmu sparc-softmmu x86_64-softmmu mips-softmmu mipsel-softmmu arm-softmmu"
+ target_list="i386-softmmu ppc-softmmu sparc-softmmu x86_64-softmmu mips-softmmu mipsel-softmmu mips64-softmmu mips64el-softmmu arm-softmmu ppc64-softmmu ppcemb-softmmu "
fi
# the following are Linux specific
- if [ "$user" = "yes" ] ; then
- target_list="i386-user arm-user armeb-user sparc-user ppc-user mips-user mipsel-user m68k-user $target_list"
+ if [ "$linux_user" = "yes" ] ; then
+ target_list="i386-linux-user arm-linux-user armeb-linux-user sparc-linux-user ppc-linux-user mips-linux-user mipsel-linux-user m68k-linux-user alpha-linux-user $target_list"
fi
+# the following are Darwin specific
+ if [ "$darwin_user" = "yes" ] ; then
+ target_list="i386-darwin-user ppc-darwin-user $target_list"
+ fi
else
target_list=`echo "$target_list" | sed -e 's/,/ /g'`
fi
@@ -433,7 +495,7 @@
}
EOF
-if $cc -o $TMPE $TMPC 2>/dev/null ; then
+if $cc -o $TMPE $TMPC 2> /dev/null ; then
$TMPE && bigendian="yes"
else
echo big/little test failed
@@ -442,7 +504,7 @@
else
# if cross compiling, cannot launch a program, so make a static guess
-if test "$cpu" = "powerpc" -o "$cpu" = "mips" -o "$cpu" = "s390" -o "$cpu" = "sparc" -o "$cpu" = "sparc64" -o "$cpu" = "m68k" -o "$cpu" = "armv4b"; then
+if test "$cpu" = "powerpc" -o "$cpu" = "mips" -o "$cpu" = "mips64" -o "$cpu" = "s390" -o "$cpu" = "sparc" -o "$cpu" = "sparc64" -o "$cpu" = "m68k" -o "$cpu" = "armv4b"; then
bigendian="yes"
fi
@@ -460,11 +522,6 @@
}
EOF
-have_gcc3_options="no"
-if $cc -fno-reorder-blocks -fno-optimize-sibling-calls -o $TMPO $TMPC 2> /dev/null ; then
- have_gcc3_options="yes"
-fi
-
##########################################
# SDL probe
@@ -493,14 +550,16 @@
if test "$_sdlversion" -lt 121 ; then
sdl_too_old=yes
else
-sdl=yes
+ if test "$cocoa" = "no" ; then
+ sdl=yes
+ fi
fi
# static link with sdl ?
if test "$sdl" = "yes" ; then
aa="no"
-`$sdl_config --static-libs | grep \\\-laa > /dev/null` && aa="yes"
-sdl_static_libs=`$sdl_config --static-libs`
+`$sdl_config --static-libs 2>/dev/null | grep \\\-laa > /dev/null` && aa="yes"
+sdl_static_libs=`$sdl_config --static-libs 2>/dev/null`
if [ "$aa" = "yes" ] ; then
sdl_static_libs="$sdl_static_libs `aalib-config --static-libs`"
fi
@@ -514,6 +573,13 @@
fi # sdl compile test
fi # cross compilation
+
+else
+ # Make sure to disable cocoa if sdl was set
+ if test "$sdl" = "yes" ; then
+ cocoa="no"
+ coreaudio="no"
+ fi
fi # -z $sdl
##########################################
@@ -536,27 +602,28 @@
fi
# Check if tools are available to build documentation.
-if [ -x "`which texi2html`" ] && [ -x "`which pod2man`" ]; then
+if [ -x "`which texi2html 2>/dev/null`" ] && \
+ [ -x "`which pod2man 2>/dev/null`" ]; then
build_docs="yes"
fi
if test "$mingw32" = "yes" ; then
-if test -z "$prefix" ; then
- prefix="/c/Program Files/Qemu"
-fi
-mandir="$prefix"
-datadir="$prefix"
-docdir="$prefix"
-bindir="$prefix"
+ if test -z "$prefix" ; then
+ prefix="/c/Program Files/Qemu"
+ fi
+ mansuffix=""
+ datasuffix=""
+ docsuffix=""
+ binsuffix=""
else
-if test -z "$prefix" ; then
- prefix="/usr/local"
+ if test -z "$prefix" ; then
+ prefix="/usr/local"
+ fi
+ mansuffix="/share/man"
+ datasuffix="/share/qemu"
+ docsuffix="/share/doc/qemu"
+ binsuffix="/bin"
fi
-mandir="$prefix/share/man"
-datadir="$prefix/share/qemu"
-docdir="$prefix/share/doc/qemu"
-bindir="$prefix/bin"
-fi
##########################################
# usb_gadgetfs headers
@@ -571,10 +638,10 @@
fi
echo "Install prefix $prefix"
-echo "BIOS directory $datadir"
-echo "binary directory $bindir"
+echo "BIOS directory $prefix$datasuffix"
+echo "binary directory $prefix$binsuffix"
if test "$mingw32" = "no" ; then
-echo "Manual directory $mandir"
+echo "Manual directory $prefix$mansuffix"
echo "ELF interp prefix $interp_prefix"
fi
echo "Source path $source_path"
@@ -613,6 +680,9 @@
fmod_support=""
fi
echo "FMOD support $fmod $fmod_support"
+if test -n "$sparc_cpu"; then
+ echo "Target Sparc Arch $sparc_cpu"
+fi
echo "kqemu support $kqemu"
echo "Documentation $build_docs"
[ ! -z "$uname_release" ] && \
@@ -634,21 +704,21 @@
echo "/* Automatically generated by configure - do not modify */" > $config_h
echo "prefix=$prefix" >> $config_mak
-echo "bindir=$bindir" >> $config_mak
-echo "mandir=$mandir" >> $config_mak
-echo "datadir=$datadir" >> $config_mak
-echo "docdir=$docdir" >> $config_mak
-echo "#define CONFIG_QEMU_SHAREDIR \"$datadir\"" >> $config_h
+echo "bindir=\${prefix}$binsuffix" >> $config_mak
+echo "mandir=\${prefix}$mansuffix" >> $config_mak
+echo "datadir=\${prefix}$datasuffix" >> $config_mak
+echo "docdir=\${prefix}$docsuffix" >> $config_mak
+echo "#define CONFIG_QEMU_SHAREDIR \"$prefix$datasuffix\"" >> $config_h
echo "MAKE=$make" >> $config_mak
echo "INSTALL=$install" >> $config_mak
echo "CC=$cc" >> $config_mak
-if test "$have_gcc3_options" = "yes" ; then
- echo "HAVE_GCC3_OPTIONS=yes" >> $config_mak
-fi
echo "HOST_CC=$host_cc" >> $config_mak
echo "AR=$ar" >> $config_mak
echo "STRIP=$strip -s -R .comment -R .note" >> $config_mak
echo "OS_CFLAGS=$OS_CFLAGS" >> $config_mak
+echo "OS_LDFLAGS=$OS_LDFLAGS" >> $config_mak
+echo "ARCH_CFLAGS=$ARCH_CFLAGS" >> $config_mak
+echo "ARCH_LDFLAGS=$ARCH_LDFLAGS" >> $config_mak
echo "CFLAGS=$CFLAGS" >> $config_mak
echo "LDFLAGS=$LDFLAGS" >> $config_mak
echo "EXESUF=$EXESUF" >> $config_mak
@@ -671,6 +741,9 @@
elif test "$cpu" = "mips" ; then
echo "ARCH=mips" >> $config_mak
echo "#define HOST_MIPS 1" >> $config_h
+elif test "$cpu" = "mips64" ; then
+ echo "ARCH=mips64" >> $config_mak
+ echo "#define HOST_MIPS64 1" >> $config_h
elif test "$cpu" = "s390" ; then
echo "ARCH=s390" >> $config_mak
echo "#define HOST_S390 1" >> $config_h
@@ -690,7 +763,7 @@
echo "ARCH=m68k" >> $config_mak
echo "#define HOST_M68K 1" >> $config_h
else
- echo "Unsupported CPU"
+ echo "Unsupported CPU = $cpu"
exit 1
fi
if test "$bigendian" = "yes" ; then
@@ -701,8 +774,14 @@
if test "$mingw32" = "yes" ; then
echo "CONFIG_WIN32=yes" >> $config_mak
echo "#define CONFIG_WIN32 1" >> $config_h
-elif test -f "/usr/include/byteswap.h" ; then
- echo "#define HAVE_BYTESWAP_H 1" >> $config_h
+else
+ cat > $TMPC << EOF
+#include <byteswap.h>
+int main(void) { return bswap_32(0); }
+EOF
+ if $cc -o $TMPE $TMPC 2> /dev/null ; then
+ echo "#define HAVE_BYTESWAP_H 1" >> $config_h
+ fi
fi
if test "$darwin" = "yes" ; then
echo "CONFIG_DARWIN=yes" >> $config_mak
@@ -711,7 +790,15 @@
if test "$solaris" = "yes" ; then
echo "CONFIG_SOLARIS=yes" >> $config_mak
echo "#define HOST_SOLARIS $solarisrev" >> $config_h
+ if test "$needs_libsunmath" = "yes" ; then
+ echo "NEEDS_LIBSUNMATH=yes" >> $config_mak
+ echo "#define NEEDS_LIBSUNMATH 1" >> $config_h
+ fi
fi
+if test -n "$sparc_cpu"; then
+ echo "CONFIG__sparc_${sparc_cpu}__=yes" >> $config_mak
+ echo "#define __sparc_${sparc_cpu}__ 1" >> $config_h
+fi
if test "$gdbstub" = "yes" ; then
echo "CONFIG_GDBSTUB=yes" >> $config_mak
echo "#define CONFIG_GDBSTUB 1" >> $config_h
@@ -795,7 +882,9 @@
[ "$target_cpu" = "sparc64" ] && target_bigendian=yes
[ "$target_cpu" = "ppc" ] && target_bigendian=yes
[ "$target_cpu" = "ppc64" ] && target_bigendian=yes
+[ "$target_cpu" = "ppcemb" ] && target_bigendian=yes
[ "$target_cpu" = "mips" ] && target_bigendian=yes
+[ "$target_cpu" = "mips64" ] && target_bigendian=yes
[ "$target_cpu" = "sh4eb" ] && target_bigendian=yes
[ "$target_cpu" = "m68k" ] && target_bigendian=yes
target_softmmu="no"
@@ -807,6 +896,16 @@
target_user_only="yes"
fi
+target_linux_user="no"
+if expr $target : '.*-linux-user' > /dev/null ; then
+ target_linux_user="yes"
+fi
+
+target_darwin_user="no"
+if expr $target : '.*-darwin-user' > /dev/null ; then
+ target_darwin_user="yes"
+fi
+
if test "$target_user_only" = "no" -a "$check_gfx" = "yes" \
-a "$sdl" = "no" -a "$cocoa" = "no" ; then
echo "ERROR: QEMU requires SDL or Cocoa for graphical output"
@@ -819,7 +918,7 @@
mkdir -p $target_dir
mkdir -p $target_dir/fpu
-if test "$target" = "arm-user" -o "$target" = "armeb-user" ; then
+if test "$target" = "arm-linux-user" -o "$target" = "armeb-linux-user" ; then
mkdir -p $target_dir/nwfpe
fi
if test "$target_user_only" = "no" ; then
@@ -874,6 +973,11 @@
echo "#define TARGET_ARCH \"ppc64\"" >> $config_h
echo "#define TARGET_PPC 1" >> $config_h
echo "#define TARGET_PPC64 1" >> $config_h
+elif test "$target_cpu" = "ppcemb" ; then
+ echo "TARGET_ARCH=ppcemb" >> $config_mak
+ echo "#define TARGET_ARCH \"ppcemb\"" >> $config_h
+ echo "#define TARGET_PPC 1" >> $config_h
+ echo "#define TARGET_PPCEMB 1" >> $config_h
elif test "$target_cpu" = "x86_64" ; then
echo "TARGET_ARCH=x86_64" >> $config_mak
echo "#define TARGET_ARCH \"x86_64\"" >> $config_h
@@ -888,6 +992,13 @@
echo "#define TARGET_MIPS 1" >> $config_h
echo "CONFIG_SOFTFLOAT=yes" >> $config_mak
echo "#define CONFIG_SOFTFLOAT 1" >> $config_h
+elif test "$target_cpu" = "mips64" -o "$target_cpu" = "mips64el" ; then
+ echo "TARGET_ARCH=mips64" >> $config_mak
+ echo "#define TARGET_ARCH \"mips64\"" >> $config_h
+ echo "#define TARGET_MIPS 1" >> $config_h
+ echo "#define TARGET_MIPS64 1" >> $config_h
+ echo "CONFIG_SOFTFLOAT=yes" >> $config_mak
+ echo "#define CONFIG_SOFTFLOAT 1" >> $config_h
elif test "$target_cpu" = "sh4" -o "$target_cpu" = "sh4eb" ; then
echo "TARGET_ARCH=sh4" >> $config_mak
echo "#define TARGET_ARCH \"sh4\"" >> $config_h
@@ -898,6 +1009,10 @@
echo "#define TARGET_ARCH \"m68k\"" >> $config_h
echo "#define TARGET_M68K 1" >> $config_h
bflt="yes"
+elif test "$target_cpu" = "alpha" ; then
+ echo "TARGET_ARCH=alpha" >> $config_mak
+ echo "#define TARGET_ARCH \"alpha\"" >> $config_h
+ echo "#define TARGET_ALPHA 1" >> $config_h
else
echo "Unsupported target CPU"
exit 1
@@ -914,6 +1029,14 @@
echo "CONFIG_USER_ONLY=yes" >> $config_mak
echo "#define CONFIG_USER_ONLY 1" >> $config_h
fi
+if test "$target_linux_user" = "yes" ; then
+ echo "CONFIG_LINUX_USER=yes" >> $config_mak
+ echo "#define CONFIG_LINUX_USER 1" >> $config_h
+fi
+if test "$target_darwin_user" = "yes" ; then
+ echo "CONFIG_DARWIN_USER=yes" >> $config_mak
+ echo "#define CONFIG_DARWIN_USER 1" >> $config_h
+fi
if test "$target_cpu" = "arm" -o "$target_cpu" = "armeb" -o "$target_cpu" = "sparc" -o "$target_cpu" = "sparc64" -o "$target_cpu" = "m68k"; then
echo "CONFIG_SOFTFLOAT=yes" >> $config_mak
Modified: trunk/src/host/qemu-neo1973/console.c
===================================================================
--- trunk/src/host/qemu-neo1973/console.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/console.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -121,6 +121,7 @@
int total_height;
int backscroll_height;
int x, y;
+ int x_saved, y_saved;
int y_displayed;
int y_base;
TextAttributes t_attrib_default; /* default text attributes */
@@ -131,10 +132,7 @@
int esc_params[MAX_ESC_PARAMS];
int nb_esc_params;
- /* kbd read handler */
- IOCanRWHandler *fd_can_read;
- IOReadHandler *fd_read;
- void *fd_opaque;
+ CharDriverState *chr;
/* fifo for key pressed */
QEMUFIFO out_fifo;
uint8_t out_fifo_buf[16];
@@ -147,7 +145,7 @@
void vga_hw_update(void)
{
- if (active_console->hw_update)
+ if (active_console && active_console->hw_update)
active_console->hw_update(active_console->hw);
}
@@ -535,21 +533,24 @@
int y, y1;
if (s == active_console) {
+ int x = s->x;
+ if (x >= s->width) {
+ x = s->width - 1;
+ }
y1 = (s->y_base + s->y) % s->total_height;
y = y1 - s->y_displayed;
if (y < 0)
y += s->total_height;
if (y < s->height) {
- c = &s->cells[y1 * s->width + s->x];
+ c = &s->cells[y1 * s->width + x];
if (show) {
TextAttributes t_attrib = s->t_attrib_default;
t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
- vga_putcharxy(s->ds, s->x, y, c->ch, &t_attrib);
+ vga_putcharxy(s->ds, x, y, c->ch, &t_attrib);
} else {
- vga_putcharxy(s->ds, s->x, y, c->ch,
- &(c->t_attrib));
+ vga_putcharxy(s->ds, x, y, c->ch, &(c->t_attrib));
}
- dpy_update(s->ds, s->x * FONT_WIDTH, y * FONT_HEIGHT,
+ dpy_update(s->ds, x * FONT_WIDTH, y * FONT_HEIGHT,
FONT_WIDTH, FONT_HEIGHT);
}
}
@@ -659,10 +660,6 @@
{
int i;
- if (s->nb_esc_params == 0) { /* ESC[m sets all attributes to default */
- s->t_attrib = s->t_attrib_default;
- return;
- }
for (i=0; i<s->nb_esc_params; i++) {
switch (s->esc_params[i]) {
case 0: /* reset all console attributes to default */
@@ -752,10 +749,21 @@
}
}
+static void console_clear_xy(TextConsole *s, int x, int y)
+{
+ int y1 = (s->y_base + y) % s->total_height;
+ TextCell *c = &s->cells[y1 * s->width + x];
+ c->ch = ' ';
+ c->t_attrib = s->t_attrib_default;
+ c++;
+ update_xy(s, x, y);
+}
+
static void console_putchar(TextConsole *s, int ch)
{
TextCell *c;
- int y1, i, x;
+ int y1, i;
+ int x, y;
switch(s->state) {
case TTY_STATE_NORM:
@@ -781,20 +789,27 @@
case '\a': /* alert aka. bell */
/* TODO: has to be implemented */
break;
+ case 14:
+ /* SI (shift in), character set 0 (ignored) */
+ break;
+ case 15:
+ /* SO (shift out), character set 1 (ignored) */
+ break;
case 27: /* esc (introducing an escape sequence) */
s->state = TTY_STATE_ESC;
break;
default:
+ if (s->x >= s->width) {
+ /* line wrap */
+ s->x = 0;
+ console_put_lf(s);
+ }
y1 = (s->y_base + s->y) % s->total_height;
c = &s->cells[y1 * s->width + s->x];
c->ch = ch;
c->t_attrib = s->t_attrib;
update_xy(s, s->x, s->y);
s->x++;
- if (s->x >= s->width) {
- s->x = 0;
- console_put_lf(s);
- }
break;
}
break;
@@ -818,32 +833,150 @@
s->nb_esc_params++;
if (ch == ';')
break;
+#ifdef DEBUG_CONSOLE
+ fprintf(stderr, "escape sequence CSI%d;%d%c, %d parameters\n",
+ s->esc_params[0], s->esc_params[1], ch, s->nb_esc_params);
+#endif
s->state = TTY_STATE_NORM;
switch(ch) {
- case 'D':
- if (s->x > 0)
- s->x--;
+ case 'A':
+ /* move cursor up */
+ if (s->esc_params[0] == 0) {
+ s->esc_params[0] = 1;
+ }
+ s->y -= s->esc_params[0];
+ if (s->y < 0) {
+ s->y = 0;
+ }
break;
+ case 'B':
+ /* move cursor down */
+ if (s->esc_params[0] == 0) {
+ s->esc_params[0] = 1;
+ }
+ s->y += s->esc_params[0];
+ if (s->y >= s->height) {
+ s->y = s->height - 1;
+ }
+ break;
case 'C':
- if (s->x < (s->width - 1))
- s->x++;
+ /* move cursor right */
+ if (s->esc_params[0] == 0) {
+ s->esc_params[0] = 1;
+ }
+ s->x += s->esc_params[0];
+ if (s->x >= s->width) {
+ s->x = s->width - 1;
+ }
break;
+ case 'D':
+ /* move cursor left */
+ if (s->esc_params[0] == 0) {
+ s->esc_params[0] = 1;
+ }
+ s->x -= s->esc_params[0];
+ if (s->x < 0) {
+ s->x = 0;
+ }
+ break;
+ case 'G':
+ /* move cursor to column */
+ s->x = s->esc_params[0] - 1;
+ if (s->x < 0) {
+ s->x = 0;
+ }
+ break;
+ case 'f':
+ case 'H':
+ /* move cursor to row, column */
+ s->x = s->esc_params[1] - 1;
+ if (s->x < 0) {
+ s->x = 0;
+ }
+ s->y = s->esc_params[0] - 1;
+ if (s->y < 0) {
+ s->y = 0;
+ }
+ break;
+ case 'J':
+ switch (s->esc_params[0]) {
+ case 0:
+ /* clear to end of screen */
+ for (y = s->y; y < s->height; y++) {
+ for (x = 0; x < s->width; x++) {
+ if (y == s->y && x < s->x) {
+ continue;
+ }
+ console_clear_xy(s, x, y);
+ }
+ }
+ break;
+ case 1:
+ /* clear from beginning of screen */
+ for (y = 0; y <= s->y; y++) {
+ for (x = 0; x < s->width; x++) {
+ if (y == s->y && x > s->x) {
+ break;
+ }
+ console_clear_xy(s, x, y);
+ }
+ }
+ break;
+ case 2:
+ /* clear entire screen */
+ for (y = 0; y <= s->height; y++) {
+ for (x = 0; x < s->width; x++) {
+ console_clear_xy(s, x, y);
+ }
+ }
+ break;
+ }
case 'K':
+ switch (s->esc_params[0]) {
+ case 0:
/* clear to eol */
- y1 = (s->y_base + s->y) % s->total_height;
for(x = s->x; x < s->width; x++) {
- c = &s->cells[y1 * s->width + x];
- c->ch = ' ';
- c->t_attrib = s->t_attrib_default;
- c++;
- update_xy(s, x, s->y);
+ console_clear_xy(s, x, s->y);
}
break;
- default:
+ case 1:
+ /* clear from beginning of line */
+ for (x = 0; x <= s->x; x++) {
+ console_clear_xy(s, x, s->y);
+ }
+ break;
+ case 2:
+ /* clear entire line */
+ for(x = 0; x < s->width; x++) {
+ console_clear_xy(s, x, s->y);
+ }
break;
}
+ break;
+ case 'm':
console_handle_escape(s);
break;
+ case 'n':
+ /* report cursor position */
+ /* TODO: send ESC[row;colR */
+ break;
+ case 's':
+ /* save cursor position */
+ s->x_saved = s->x;
+ s->y_saved = s->y;
+ break;
+ case 'u':
+ /* restore cursor position */
+ s->x = s->x_saved;
+ s->y = s->y_saved;
+ break;
+ default:
+#ifdef DEBUG_CONSOLE
+ fprintf(stderr, "unhandled escape character '%c'\n", ch);
+#endif
+ break;
+ }
+ break;
}
}
}
@@ -884,16 +1017,6 @@
return len;
}
-static void console_chr_add_read_handler(CharDriverState *chr,
- IOCanRWHandler *fd_can_read,
- IOReadHandler *fd_read, void *opaque)
-{
- TextConsole *s = chr->opaque;
- s->fd_can_read = fd_can_read;
- s->fd_read = fd_read;
- s->fd_opaque = opaque;
-}
-
static void console_send_event(CharDriverState *chr, int event)
{
TextConsole *s = chr->opaque;
@@ -915,14 +1038,14 @@
int len;
uint8_t buf[16];
- len = s->fd_can_read(s->fd_opaque);
+ len = qemu_chr_can_read(s->chr);
if (len > s->out_fifo.count)
len = s->out_fifo.count;
if (len > 0) {
if (len > sizeof(buf))
len = sizeof(buf);
qemu_fifo_read(&s->out_fifo, buf, len);
- s->fd_read(s->fd_opaque, buf, len);
+ qemu_chr_read(s->chr, buf, len);
}
/* characters are pending: we send them a bit later (XXX:
horrible, should change char device API) */
@@ -973,7 +1096,7 @@
} else {
*q++ = keysym;
}
- if (s->fd_read) {
+ if (s->chr->chr_read) {
qemu_fifo_write(&s->out_fifo, buf, q - buf);
kbd_send_chars(s);
}
@@ -1049,9 +1172,9 @@
}
chr->opaque = s;
chr->chr_write = console_puts;
- chr->chr_add_read_handler = console_chr_add_read_handler;
chr->chr_send_event = console_send_event;
+ s->chr = chr;
s->out_fifo.buf = s->out_fifo_buf;
s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
s->kbd_timer = qemu_new_timer(rt_clock, kbd_send_chars, s);
Modified: trunk/src/host/qemu-neo1973/cpu-all.h
===================================================================
--- trunk/src/host/qemu-neo1973/cpu-all.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/cpu-all.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -20,7 +20,7 @@
#ifndef CPU_ALL_H
#define CPU_ALL_H
-#if defined(__arm__) || defined(__sparc__)
+#if defined(__arm__) || defined(__sparc__) || defined(__mips__)
#define WORDS_ALIGNED
#endif
@@ -644,12 +644,14 @@
#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)
@@ -746,6 +748,13 @@
#define cpu_gen_code cpu_sh4_gen_code
#define cpu_signal_handler cpu_sh4_signal_handler
+#elif defined(TARGET_ALPHA)
+#define CPUState CPUAlphaState
+#define cpu_init cpu_alpha_init
+#define cpu_exec cpu_alpha_exec
+#define cpu_gen_code cpu_alpha_gen_code
+#define cpu_signal_handler cpu_alpha_signal_handler
+
#else
#error unsupported target CPU
@@ -754,11 +763,17 @@
#endif /* SINGLE_CPU_DEFINES */
+CPUState *cpu_copy(CPUState *env);
+
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 cpu_abort(CPUState *env, const char *fmt, ...);
+void cpu_abort(CPUState *env, const char *fmt, ...)
+ __attribute__ ((__format__ (__printf__, 2, 3)));
extern CPUState *first_cpu;
extern CPUState *cpu_single_env;
extern int code_copy_enabled;
@@ -770,10 +785,13 @@
#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. */
void cpu_interrupt(CPUState *s, int mask);
void cpu_reset_interrupt(CPUState *env, int mask);
+int cpu_watchpoint_insert(CPUState *env, target_ulong addr);
+int cpu_watchpoint_remove(CPUState *env, target_ulong addr);
int cpu_breakpoint_insert(CPUState *env, target_ulong pc);
int cpu_breakpoint_remove(CPUState *env, target_ulong pc);
void cpu_single_step(CPUState *env, int enabled);
@@ -782,7 +800,7 @@
/* 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_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr);
+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)
@@ -848,6 +866,8 @@
unsigned long size,
unsigned long phys_offset);
uint32_t cpu_get_physical_page_desc(target_phys_addr_t addr);
+ram_addr_t qemu_ram_alloc(unsigned int size);
+void qemu_ram_free(ram_addr_t addr);
int cpu_register_io_memory(int io_index,
CPUReadMemoryFunc **mem_read,
CPUWriteMemoryFunc **mem_write,
@@ -872,6 +892,7 @@
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);
@@ -980,7 +1001,7 @@
return val;
}
-#elif defined(__sparc_v9__)
+#elif defined(__sparc_v8plus__) || defined(__sparc_v8plusa__) || defined(__sparc_v9__)
static inline int64_t cpu_get_real_ticks (void)
{
@@ -1001,10 +1022,31 @@
return rval.i64;
#endif
}
+
+#elif defined(__mips__)
+
+static inline int64_t cpu_get_real_ticks(void)
+{
+#if __mips_isa_rev >= 2
+ uint32_t count;
+ static uint32_t cyc_per_count = 0;
+
+ if (!cyc_per_count)
+ __asm__ __volatile__("rdhwr %0, $3" : "=r" (cyc_per_count));
+
+ __asm__ __volatile__("rdhwr %1, $2" : "=r" (count));
+ return (int64_t)(count * cyc_per_count);
#else
+ /* FIXME */
+ static int64_t ticks = 0;
+ return ticks++;
+#endif
+}
+
+#else
/* The host CPU doesn't have an easily accessible cycle counter.
- Just return a monotonically increasing vlue. This will be totally wrong,
- but hopefully better than nothing. */
+ 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;
Modified: trunk/src/host/qemu-neo1973/cpu-defs.h
===================================================================
--- trunk/src/host/qemu-neo1973/cpu-defs.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/cpu-defs.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -44,10 +44,12 @@
typedef int32_t target_long;
typedef uint32_t target_ulong;
#define TARGET_FMT_lx "%08x"
+#define TARGET_FMT_ld "%d"
#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
#else
#error TARGET_LONG_SIZE undefined
#endif
@@ -60,8 +62,10 @@
#if TARGET_PHYS_ADDR_BITS == 32
typedef uint32_t target_phys_addr_t;
+#define TARGET_FMT_plx "%08x"
#elif TARGET_PHYS_ADDR_BITS == 64
typedef uint64_t target_phys_addr_t;
+#define TARGET_FMT_plx "%016" PRIx64
#else
#error TARGET_PHYS_ADDR_BITS undefined
#endif
@@ -76,6 +80,7 @@
#define EXCP_DEBUG 0x10002 /* cpu stopped after a breakpoint or singlestep */
#define EXCP_HALTED 0x10003 /* cpu is halted (waiting for external event) */
#define MAX_BREAKPOINTS 32
+#define MAX_WATCHPOINTS 32
#define TB_JMP_CACHE_BITS 12
#define TB_JMP_CACHE_SIZE (1 << TB_JMP_CACHE_BITS)
@@ -105,6 +110,15 @@
target_phys_addr_t addend;
} CPUTLBEntry;
+/* Alpha has 4 different running levels */
+#if defined(TARGET_ALPHA)
+#define NB_MMU_MODES 4
+#elif defined(TARGET_PPC64H) /* PowerPC 64 with hypervisor mode support */
+#define NB_MMU_MODES 3
+#else
+#define NB_MMU_MODES 2
+#endif
+
#define CPU_COMMON \
struct TranslationBlock *current_tb; /* currently executing TB */ \
/* soft mmu support */ \
@@ -116,7 +130,7 @@
target_ulong mem_write_vaddr; /* target virtual addr at which the \
memory was written */ \
/* 0 = kernel, 1 = user */ \
- CPUTLBEntry tlb_table[2][CPU_TLB_SIZE]; \
+ CPUTLBEntry tlb_table[NB_MMU_MODES][CPU_TLB_SIZE]; \
struct TranslationBlock *tb_jmp_cache[TB_JMP_CACHE_SIZE]; \
\
/* from this point: preserved by CPU reset */ \
@@ -125,6 +139,13 @@
int nb_breakpoints; \
int singlestep_enabled; \
\
+ struct { \
+ target_ulong vaddr; \
+ int is_ram; \
+ } watchpoint[MAX_WATCHPOINTS]; \
+ int nb_watchpoints; \
+ int watchpoint_hit; \
+ \
void *next_cpu; /* next CPU sharing TB cache */ \
int cpu_index; /* CPU index (informative) */ \
/* user data */ \
Modified: trunk/src/host/qemu-neo1973/cpu-exec.c
===================================================================
--- trunk/src/host/qemu-neo1973/cpu-exec.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/cpu-exec.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -40,7 +40,8 @@
//#define DEBUG_EXEC
//#define DEBUG_SIGNAL
-#if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_M68K)
+#if defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_M68K) || \
+ defined(TARGET_ALPHA)
/* XXX: unify with i386 target */
void cpu_loop_exit(void)
{
@@ -202,6 +203,10 @@
flags = env->sr & (SR_MD | SR_RB);
cs_base = 0; /* XXXXX */
pc = env->pc;
+#elif defined(TARGET_ALPHA)
+ flags = env->ps;
+ cs_base = 0;
+ pc = env->pc;
#else
#error unsupported CPU
#endif
@@ -226,43 +231,16 @@
int cpu_exec(CPUState *env1)
{
- int saved_T0, saved_T1;
-#if defined(reg_T2)
- int saved_T2;
-#endif
- CPUState *saved_env;
-#if defined(TARGET_I386)
-#ifdef reg_EAX
- int saved_EAX;
-#endif
-#ifdef reg_ECX
- int saved_ECX;
-#endif
-#ifdef reg_EDX
- int saved_EDX;
-#endif
-#ifdef reg_EBX
- int saved_EBX;
-#endif
-#ifdef reg_ESP
- int saved_ESP;
-#endif
-#ifdef reg_EBP
- int saved_EBP;
-#endif
-#ifdef reg_ESI
- int saved_ESI;
-#endif
-#ifdef reg_EDI
- int saved_EDI;
-#endif
-#elif defined(TARGET_SPARC)
+#define DECLARE_HOST_REGS 1
+#include "hostregs_helper.h"
+#if defined(TARGET_SPARC)
#if defined(reg_REGWPTR)
uint32_t *saved_regwptr;
#endif
#endif
#if defined(__sparc__) && !defined(HOST_SOLARIS)
- int saved_i7, tmp_T0;
+ int saved_i7;
+ target_ulong tmp_T0;
#endif
int ret, interrupt_request;
void (*gen_func)(void);
@@ -283,8 +261,7 @@
#elif defined(TARGET_PPC)
if (env1->halted) {
if (env1->msr[MSR_EE] &&
- (env1->interrupt_request &
- (CPU_INTERRUPT_HARD | CPU_INTERRUPT_TIMER))) {
+ (env1->interrupt_request & CPU_INTERRUPT_HARD)) {
env1->halted = 0;
} else {
return EXCP_HALTED;
@@ -302,7 +279,8 @@
#elif defined(TARGET_ARM)
if (env1->halted) {
/* An interrupt wakes the CPU even if the I and F CPSR bits are
- set. */
+ set. We use EXITTB to silently wake CPU without causing an
+ actual interrupt. */
if (env1->interrupt_request &
(CPU_INTERRUPT_FIQ | CPU_INTERRUPT_HARD | CPU_INTERRUPT_EXITTB)) {
env1->halted = 0;
@@ -319,49 +297,28 @@
return EXCP_HALTED;
}
}
+#elif defined(TARGET_ALPHA)
+ if (env1->halted) {
+ if (env1->interrupt_request & CPU_INTERRUPT_HARD) {
+ env1->halted = 0;
+ } else {
+ return EXCP_HALTED;
+ }
+ }
#endif
cpu_single_env = env1;
/* first we save global registers */
- saved_env = env;
+#define SAVE_HOST_REGS 1
+#include "hostregs_helper.h"
env = env1;
- saved_T0 = T0;
- saved_T1 = T1;
-#if defined(reg_T2)
- saved_T2 = T2;
-#endif
#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)
-#ifdef reg_EAX
- saved_EAX = EAX;
-#endif
-#ifdef reg_ECX
- saved_ECX = ECX;
-#endif
-#ifdef reg_EDX
- saved_EDX = EDX;
-#endif
-#ifdef reg_EBX
- saved_EBX = EBX;
-#endif
-#ifdef reg_ESP
- saved_ESP = ESP;
-#endif
-#ifdef reg_EBP
- saved_EBP = EBP;
-#endif
-#ifdef reg_ESI
- saved_ESI = ESI;
-#endif
-#ifdef reg_EDI
- saved_EDI = EDI;
-#endif
-
env_to_regs();
/* put eflags in CPU temporary format */
CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
@@ -381,6 +338,8 @@
#elif defined(TARGET_MIPS)
#elif defined(TARGET_SH4)
/* XXXXX */
+#elif defined(TARGET_ALPHA)
+ env_to_regs();
#else
#error unsupported target CPU
#endif
@@ -417,6 +376,8 @@
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_MIPS)
@@ -427,6 +388,8 @@
do_interrupt(env);
#elif defined(TARGET_SH4)
do_interrupt(env);
+#elif defined(TARGET_ALPHA)
+ do_interrupt(env);
#endif
}
env->exception_index = -1;
@@ -465,6 +428,20 @@
#endif
interrupt_request = env->interrupt_request;
if (__builtin_expect(interrupt_request, 0)) {
+ 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)
+ 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_SMI) &&
!(env->hflags & HF_SMM_MASK)) {
@@ -499,43 +476,27 @@
cpu_ppc_reset(env);
}
#endif
- if (msr_ee != 0) {
- if ((interrupt_request & CPU_INTERRUPT_HARD)) {
- /* Raise it */
- env->exception_index = EXCP_EXTERNAL;
- env->error_code = 0;
- do_interrupt(env);
+ if (interrupt_request & CPU_INTERRUPT_HARD) {
+ ppc_hw_interrupt(env);
+ if (env->pending_interrupts == 0)
env->interrupt_request &= ~CPU_INTERRUPT_HARD;
#if defined(__sparc__) && !defined(HOST_SOLARIS)
- tmp_T0 = 0;
+ tmp_T0 = 0;
#else
- T0 = 0;
+ 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)
if ((interrupt_request & CPU_INTERRUPT_HARD) &&
+ (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) &&
(env->CP0_Status & (1 << CP0St_IE)) &&
- (env->CP0_Status & env->CP0_Cause & 0x0000FF00) &&
- !(env->hflags & MIPS_HFLAG_EXL) &&
- !(env->hflags & MIPS_HFLAG_ERL) &&
+ !(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);
- env->interrupt_request &= ~CPU_INTERRUPT_HARD;
#if defined(__sparc__) && !defined(HOST_SOLARIS)
tmp_T0 = 0;
#else
@@ -563,12 +524,7 @@
} else if (interrupt_request & CPU_INTERRUPT_TIMER) {
//do_interrupt(0, 0, 0, 0, 0);
env->interrupt_request &= ~CPU_INTERRUPT_TIMER;
- } else if (interrupt_request & CPU_INTERRUPT_HALT) {
- env->interrupt_request &= ~CPU_INTERRUPT_HALT;
- env->halted = 1;
- env->exception_index = EXCP_HLT;
- cpu_loop_exit();
- }
+ }
#elif defined(TARGET_ARM)
if (interrupt_request & CPU_INTERRUPT_FIQ
&& !(env->uncached_cpsr & CPSR_F)) {
@@ -580,14 +536,12 @@
env->exception_index = EXCP_IRQ;
do_interrupt(env);
}
- if (interrupt_request & CPU_INTERRUPT_HALT) {
- env->interrupt_request &= ~CPU_INTERRUPT_HALT;
- env->halted = 1;
- env->exception_index = EXCP_HLT;
- cpu_loop_exit();
- }
#elif defined(TARGET_SH4)
/* XXXXX */
+#elif defined(TARGET_ALPHA)
+ if (interrupt_request & CPU_INTERRUPT_HARD) {
+ do_interrupt(env);
+ }
#endif
/* Don't use the cached interupt_request value,
do_interrupt may have updated the EXITTB flag. */
@@ -656,6 +610,8 @@
cpu_dump_state(env, logfile, fprintf, 0);
#elif defined(TARGET_SH4)
cpu_dump_state(env, logfile, fprintf, 0);
+#elif defined(TARGET_ALPHA)
+ cpu_dump_state(env, logfile, fprintf, 0);
#else
#error unsupported target CPU
#endif
@@ -706,6 +662,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__)
@@ -833,32 +790,6 @@
#endif
/* restore flags in standard format */
env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
-
- /* restore global registers */
-#ifdef reg_EAX
- EAX = saved_EAX;
-#endif
-#ifdef reg_ECX
- ECX = saved_ECX;
-#endif
-#ifdef reg_EDX
- EDX = saved_EDX;
-#endif
-#ifdef reg_EBX
- EBX = saved_EBX;
-#endif
-#ifdef reg_ESP
- ESP = saved_ESP;
-#endif
-#ifdef reg_EBP
- EBP = saved_EBP;
-#endif
-#ifdef reg_ESI
- ESI = saved_ESI;
-#endif
-#ifdef reg_EDI
- EDI = saved_EDI;
-#endif
#elif defined(TARGET_ARM)
/* XXX: Save/restore host fpu exception state?. */
#elif defined(TARGET_SPARC)
@@ -873,19 +804,18 @@
| env->cc_dest | (env->cc_x << 4);
#elif defined(TARGET_MIPS)
#elif defined(TARGET_SH4)
+#elif defined(TARGET_ALPHA)
/* XXXXX */
#else
#error unsupported target CPU
#endif
+
+ /* restore global registers */
#if defined(__sparc__) && !defined(HOST_SOLARIS)
asm volatile ("mov %0, %%i7" : : "r" (saved_i7));
#endif
- T0 = saved_T0;
- T1 = saved_T1;
-#if defined(reg_T2)
- T2 = saved_T2;
-#endif
- env = saved_env;
+#include "hostregs_helper.h"
+
/* fail safe : never use cpu_single_env outside cpu_exec() */
cpu_single_env = NULL;
return ret;
@@ -1261,12 +1191,69 @@
/* never comes here */
return 1;
}
+
+#elif defined (TARGET_ALPHA)
+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)
+ 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_alpha_handle_mmu_fault(env, address, is_write, 1, 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);
+ }
+#if 0
+ printf("PF exception: NIP=0x%08x error=0x%x %p\n",
+ env->nip, env->error_code, tb);
+#endif
+ /* we restore the process signal mask as the sigreturn should
+ do it (XXX: use sigsetjmp) */
+ sigprocmask(SIG_SETMASK, old_set, NULL);
+ cpu_loop_exit();
+ /* never comes here */
+ return 1;
+}
#else
#error unsupported target CPU
#endif
#if defined(__i386__)
+#if defined(__APPLE__)
+# include <sys/ucontext.h>
+
+# 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)
+#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])
+#endif
+
#if defined(USE_CODE_COPY)
static void cpu_send_trap(unsigned long pc, int trap,
struct ucontext *uc)
@@ -1287,9 +1274,10 @@
}
#endif
-int cpu_signal_handler(int host_signum, struct siginfo *info,
+int cpu_signal_handler(int host_signum, void *pinfo,
void *puc)
{
+ siginfo_t *info = pinfo;
struct ucontext *uc = puc;
unsigned long pc;
int trapno;
@@ -1300,8 +1288,8 @@
#define REG_ERR ERR
#define REG_TRAPNO TRAPNO
#endif
- pc = uc->uc_mcontext.gregs[REG_EIP];
- trapno = uc->uc_mcontext.gregs[REG_TRAPNO];
+ pc = EIP_sig(uc);
+ trapno = TRAP_sig(uc);
#if defined(TARGET_I386) && defined(USE_CODE_COPY)
if (trapno == 0x00 || trapno == 0x05) {
/* send division by zero or bound exception */
@@ -1311,15 +1299,16 @@
#endif
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
trapno == 0xe ?
- (uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0,
+ (ERROR_sig(uc) >> 1) & 1 : 0,
&uc->uc_sigmask, puc);
}
#elif defined(__x86_64__)
-int cpu_signal_handler(int host_signum, struct siginfo *info,
+int cpu_signal_handler(int host_signum, void *pinfo,
void *puc)
{
+ siginfo_t *info = pinfo;
struct ucontext *uc = puc;
unsigned long pc;
@@ -1381,9 +1370,10 @@
# define TRAP_sig(context) EXCEPREG_sig(exception, context) /* number of powerpc exception taken */
#endif /* __APPLE__ */
-int cpu_signal_handler(int host_signum, struct siginfo *info,
+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;
@@ -1404,9 +1394,10 @@
#elif defined(__alpha__)
-int cpu_signal_handler(int host_signum, struct siginfo *info,
+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;
@@ -1433,9 +1424,10 @@
}
#elif defined(__sparc__)
-int cpu_signal_handler(int host_signum, struct siginfo *info,
+int cpu_signal_handler(int host_signum, void *pinfo,
void *puc)
{
+ siginfo_t *info = pinfo;
uint32_t *regs = (uint32_t *)(info + 1);
void *sigmask = (regs + 20);
unsigned long pc;
@@ -1466,9 +1458,10 @@
#elif defined(__arm__)
-int cpu_signal_handler(int host_signum, struct siginfo *info,
+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;
@@ -1483,9 +1476,10 @@
#elif defined(__mc68000)
-int cpu_signal_handler(int host_signum, struct siginfo *info,
+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;
@@ -1505,8 +1499,9 @@
# define __ISR_VALID 1
#endif
-int cpu_signal_handler(int host_signum, struct siginfo *info, void *puc)
+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;
@@ -1533,9 +1528,10 @@
#elif defined(__s390__)
-int cpu_signal_handler(int host_signum, struct siginfo *info,
+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;
@@ -1544,10 +1540,25 @@
/* XXX: compute is_write */
is_write = 0;
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
- is_write,
- &uc->uc_sigmask, puc);
+ 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);
+}
+
#else
#error host CPU specific signal handler needed
Added: trunk/src/host/qemu-neo1973/darwin-user/commpage.c
===================================================================
--- trunk/src/host/qemu-neo1973/darwin-user/commpage.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/darwin-user/commpage.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,358 @@
+ /*
+ * Commpage syscalls
+ *
+ * Copyright (c) 2006 Pierre d'Herbemont
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <mach/message.h>
+#include <mach/mach.h>
+#include <mach/mach_time.h>
+#include <sys/time.h>
+#include <sys/mman.h>
+#include <libkern/OSAtomic.h>
+
+#include "qemu.h"
+
+//#define DEBUG_COMMPAGE
+
+#ifdef DEBUG_COMMPAGE
+# define DPRINTF(...) do { if(loglevel) fprintf(logfile, __VA_ARGS__); printf(__VA_ARGS__); } while(0)
+#else
+# define DPRINTF(...) do { if(loglevel) fprintf(logfile, __VA_ARGS__); } while(0)
+#endif
+
+/********************************************************************
+ * Commpage definitions
+ */
+#ifdef TARGET_I386
+/* Reserve space for the commpage see xnu/osfmk/i386/cpu_capabilities.h */
+# define COMMPAGE_START (-16 * 4096) /* base address is -20 * 4096 */
+# define COMMPAGE_SIZE (0x1240) /* _COMM_PAGE_AREA_LENGTH is 19 * 4096 */
+#elif defined(TARGET_PPC)
+/* Reserve space for the commpage see xnu/osfmk/ppc/cpu_capabilities.h */
+# define COMMPAGE_START (-8*4096)
+# define COMMPAGE_SIZE (2*4096) /* its _COMM_PAGE_AREA_USED but _COMM_PAGE_AREA_LENGTH is 7*4096 */
+#endif
+
+void do_compare_and_swap32(void *cpu_env, int num);
+void do_compare_and_swap64(void *cpu_env, int num);
+void do_add_atomic_word32(void *cpu_env, int num);
+void do_cgettimeofday(void *cpu_env, int num, uint32_t arg1);
+void do_nanotime(void *cpu_env, int num);
+
+void unimpl_commpage(void *cpu_env, int num);
+
+typedef void (*commpage_8args_function_t)(uint32_t arg1, uint32_t arg2, uint32_t arg3,
+ uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7,
+ uint32_t arg8);
+typedef void (*commpage_indirect_function_t)(void *cpu_env, int num, uint32_t arg1,
+ uint32_t arg2, uint32_t arg3, uint32_t arg4, uint32_t arg5,
+ uint32_t arg6, uint32_t arg7, uint32_t arg8);
+
+#define HAS_PTR 0x10
+#define NO_PTR 0x20
+#define CALL_DIRECT 0x1
+#define CALL_INDIRECT 0x2
+
+#define COMMPAGE_ENTRY(name, nargs, offset, func, options) \
+ { #name, offset, nargs, options, (commpage_8args_function_t)func }
+
+struct commpage_entry {
+ char * name;
+ int offset;
+ int nargs;
+ char options;
+ commpage_8args_function_t function;
+};
+
+static inline int commpage_code_num(struct commpage_entry *entry)
+{
+ if((entry->options & HAS_PTR))
+ return entry->offset + 4;
+ else
+ return entry->offset;
+}
+
+static inline int commpage_is_indirect(struct commpage_entry *entry)
+{
+ return !(entry->options & CALL_DIRECT);
+}
+
+/********************************************************************
+ * Commpage entry
+ */
+static struct commpage_entry commpage_entries[] =
+{
+ COMMPAGE_ENTRY(compare_and_swap32, 0, 0x080, do_compare_and_swap32, CALL_INDIRECT | HAS_PTR),
+ COMMPAGE_ENTRY(compare_and_swap64, 0, 0x0c0, do_compare_and_swap64, CALL_INDIRECT | HAS_PTR),
+ COMMPAGE_ENTRY(enqueue, 0, 0x100, unimpl_commpage, CALL_INDIRECT),
+ COMMPAGE_ENTRY(dequeue, 0, 0x140, unimpl_commpage, CALL_INDIRECT),
+ COMMPAGE_ENTRY(memory_barrier, 0, 0x180, unimpl_commpage, CALL_INDIRECT),
+ COMMPAGE_ENTRY(add_atomic_word32, 0, 0x1a0, do_add_atomic_word32, CALL_INDIRECT | HAS_PTR),
+ COMMPAGE_ENTRY(add_atomic_word64, 0, 0x1c0, unimpl_commpage, CALL_INDIRECT | HAS_PTR),
+
+ COMMPAGE_ENTRY(mach_absolute_time, 0, 0x200, unimpl_commpage, CALL_INDIRECT),
+ COMMPAGE_ENTRY(spinlock_try, 1, 0x220, unimpl_commpage, CALL_INDIRECT),
+ COMMPAGE_ENTRY(spinlock_lock, 1, 0x260, OSSpinLockLock, CALL_DIRECT),
+ COMMPAGE_ENTRY(spinlock_unlock, 1, 0x2a0, OSSpinLockUnlock, CALL_DIRECT),
+ COMMPAGE_ENTRY(pthread_getspecific, 0, 0x2c0, unimpl_commpage, CALL_INDIRECT),
+ COMMPAGE_ENTRY(gettimeofday, 1, 0x2e0, do_cgettimeofday, CALL_INDIRECT),
+ COMMPAGE_ENTRY(sys_dcache_flush, 0, 0x4e0, unimpl_commpage, CALL_INDIRECT),
+ COMMPAGE_ENTRY(sys_icache_invalidate, 0, 0x520, unimpl_commpage, CALL_INDIRECT),
+ COMMPAGE_ENTRY(pthread_self, 0, 0x580, unimpl_commpage, CALL_INDIRECT),
+
+ COMMPAGE_ENTRY(relinquish, 0, 0x5c0, unimpl_commpage, CALL_INDIRECT),
+
+#ifdef TARGET_I386
+ COMMPAGE_ENTRY(bts, 0, 0x5e0, unimpl_commpage, CALL_INDIRECT),
+ COMMPAGE_ENTRY(btc, 0, 0x5f0, unimpl_commpage, CALL_INDIRECT),
+#endif
+
+ COMMPAGE_ENTRY(bzero, 2, 0x600, bzero, CALL_DIRECT),
+ COMMPAGE_ENTRY(bcopy, 3, 0x780, bcopy, CALL_DIRECT),
+ COMMPAGE_ENTRY(memcpy, 3, 0x7a0, memcpy, CALL_DIRECT),
+
+#ifdef TARGET_I386
+ COMMPAGE_ENTRY(old_nanotime, 0, 0xf80, do_nanotime, CALL_INDIRECT),
+ COMMPAGE_ENTRY(memset_pattern, 0, 0xf80, unimpl_commpage, CALL_INDIRECT),
+ COMMPAGE_ENTRY(long_copy, 0, 0x1200, unimpl_commpage, CALL_INDIRECT),
+
+ COMMPAGE_ENTRY(sysintegrity, 0, 0x1600, unimpl_commpage, CALL_INDIRECT),
+
+ COMMPAGE_ENTRY(nanotime, 0, 0x1700, do_nanotime, CALL_INDIRECT),
+#elif TARGET_PPC
+ COMMPAGE_ENTRY(compare_and_swap32b, 0, 0xf80, unimpl_commpage, CALL_INDIRECT),
+ COMMPAGE_ENTRY(compare_and_swap64b, 0, 0xfc0, unimpl_commpage, CALL_INDIRECT),
+ COMMPAGE_ENTRY(memset_pattern, 0, 0x1000, unimpl_commpage, CALL_INDIRECT),
+ COMMPAGE_ENTRY(bigcopy, 0, 0x1140, unimpl_commpage, CALL_INDIRECT),
+#endif
+};
+
+
+/********************************************************************
+ * Commpage backdoor
+ */
+static inline void print_commpage_entry(struct commpage_entry entry)
+{
+ printf("@0x%x %s\n", entry.offset, entry.name);
+}
+
+static inline void install_commpage_backdoor_for_entry(struct commpage_entry entry)
+{
+#ifdef TARGET_I386
+ char * commpage = (char*)(COMMPAGE_START+entry.offset);
+ int c = 0;
+ if(entry.options & HAS_PTR)
+ {
+ commpage[c++] = (COMMPAGE_START+entry.offset+4) & 0xff;
+ commpage[c++] = ((COMMPAGE_START+entry.offset+4) >> 8) & 0xff;
+ commpage[c++] = ((COMMPAGE_START+entry.offset+4) >> 16) & 0xff;
+ commpage[c++] = ((COMMPAGE_START+entry.offset+4) >> 24) & 0xff;
+ }
+ commpage[c++] = 0xcd;
+ commpage[c++] = 0x79; /* int 0x79 */
+ commpage[c++] = 0xc3; /* ret */
+#else
+ qerror("can't install the commpage on this arch\n");
+#endif
+}
+
+/********************************************************************
+ * Commpage initialization
+ */
+void commpage_init(void)
+{
+#if (defined(__i386__) ^ defined(TARGET_I386)) || (defined(__powerpc__) ^ defined(TARGET_PPC))
+ int i;
+ void * commpage = (void *)target_mmap( COMMPAGE_START, COMMPAGE_SIZE,
+ PROT_WRITE | PROT_READ, MAP_ANONYMOUS | MAP_FIXED, -1, 0);
+ if((int)commpage != COMMPAGE_START)
+ qerror("can't allocate the commpage\n");
+
+ bzero(commpage, COMMPAGE_SIZE);
+
+ /* XXX: commpage data not handled */
+
+ for(i = 0; i < sizeof(commpage_entries)/sizeof(commpage_entries[0]); i++)
+ install_commpage_backdoor_for_entry(commpage_entries[i]);
+#else
+ /* simply map our pages so they can be executed
+ XXX: we don't really want to do that since in the ppc on ppc situation we may
+ not able to run commpages host optimized instructions (like G5's on a G5),
+ hence this is sometimes a broken fix. */
+ page_set_flags(COMMPAGE_START, COMMPAGE_START+COMMPAGE_SIZE, PROT_EXEC | PROT_READ | PAGE_VALID);
+#endif
+}
+
+/********************************************************************
+ * Commpage implementation
+ */
+void do_compare_and_swap32(void *cpu_env, int num)
+{
+#ifdef TARGET_I386
+ uint32_t old = ((CPUX86State*)cpu_env)->regs[R_EAX];
+ uint32_t *value = (uint32_t*)((CPUX86State*)cpu_env)->regs[R_ECX];
+ DPRINTF("commpage: compare_and_swap32(%x,new,%p)\n", old, value);
+
+ if(value && old == tswap32(*value))
+ {
+ uint32_t new = ((CPUX86State*)cpu_env)->regs[R_EDX];
+ *value = tswap32(new);
+ /* set zf flag */
+ ((CPUX86State*)cpu_env)->eflags |= 0x40;
+ }
+ else
+ {
+ ((CPUX86State*)cpu_env)->regs[R_EAX] = tswap32(*value);
+ /* unset zf flag */
+ ((CPUX86State*)cpu_env)->eflags &= ~0x40;
+ }
+#else
+ qerror("do_compare_and_swap32 unimplemented");
+#endif
+}
+
+void do_compare_and_swap64(void *cpu_env, int num)
+{
+#ifdef TARGET_I386
+ /* OSAtomicCompareAndSwap64 is not available on non 64 bits ppc, here is a raw implementation */
+ uint64_t old, new, swapped_val;
+ uint64_t *value = (uint64_t*)((CPUX86State*)cpu_env)->regs[R_ESI];
+ old = (uint64_t)((uint64_t)((CPUX86State*)cpu_env)->regs[R_EDX]) << 32 | (uint64_t)((CPUX86State*)cpu_env)->regs[R_EAX];
+
+ DPRINTF("commpage: compare_and_swap64(%llx,new,%p)\n", old, value);
+ swapped_val = tswap64(*value);
+
+ if(old == swapped_val)
+ {
+ new = (uint64_t)((uint64_t)((CPUX86State*)cpu_env)->regs[R_ECX]) << 32 | (uint64_t)((CPUX86State*)cpu_env)->regs[R_EBX];
+ *value = tswap64(new);
+ /* set zf flag */
+ ((CPUX86State*)cpu_env)->eflags |= 0x40;
+ }
+ else
+ {
+ ((CPUX86State*)cpu_env)->regs[R_EAX] = (uint32_t)(swapped_val);
+ ((CPUX86State*)cpu_env)->regs[R_EDX] = (uint32_t)(swapped_val >> 32);
+ /* unset zf flag */
+ ((CPUX86State*)cpu_env)->eflags &= ~0x40;
+ }
+#else
+ qerror("do_compare_and_swap64 unimplemented");
+#endif
+}
+
+void do_add_atomic_word32(void *cpu_env, int num)
+{
+#ifdef TARGET_I386
+ uint32_t amt = ((CPUX86State*)cpu_env)->regs[R_EAX];
+ uint32_t *value = (uint32_t*)((CPUX86State*)cpu_env)->regs[R_EDX];
+ uint32_t swapped_value = tswap32(*value);
+
+ DPRINTF("commpage: add_atomic_word32(%x,%p)\n", amt, value);
+
+ /* old value in EAX */
+ ((CPUX86State*)cpu_env)->regs[R_EAX] = swapped_value;
+ *value = tswap32(swapped_value + amt);
+#else
+ qerror("do_add_atomic_word32 unimplemented");
+#endif
+}
+
+void do_cgettimeofday(void *cpu_env, int num, uint32_t arg1)
+{
+#ifdef TARGET_I386
+ extern int __commpage_gettimeofday(struct timeval *);
+ DPRINTF("commpage: gettimeofday(0x%x)\n", arg1);
+ struct timeval *time = (struct timeval *)arg1;
+ int ret = __commpage_gettimeofday(time);
+ tswap32s((uint32_t*)&time->tv_sec);
+ tswap32s((uint32_t*)&time->tv_usec);
+ ((CPUX86State*)cpu_env)->regs[R_EAX] = ret; /* Success */
+#else
+ qerror("do_gettimeofday unimplemented");
+#endif
+}
+
+void do_nanotime(void *cpu_env, int num)
+{
+#ifdef TARGET_I386
+ uint64_t t = mach_absolute_time();
+ ((CPUX86State*)cpu_env)->regs[R_EAX] = (int)(t & 0xffffffff);
+ ((CPUX86State*)cpu_env)->regs[R_EDX] = (int)((t >> 32) & 0xffffffff);
+#else
+ qerror("do_nanotime unimplemented");
+#endif
+}
+
+void unimpl_commpage(void *cpu_env, int num)
+{
+ qerror("qemu: commpage function 0x%x not implemented\n", num);
+}
+
+/********************************************************************
+ * do_commpage - called by the main cpu loop
+ */
+void
+do_commpage(void *cpu_env, int num, uint32_t arg1, uint32_t arg2, uint32_t arg3,
+ uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7,
+ uint32_t arg8)
+{
+ int i, found = 0;
+
+ arg1 = tswap32(arg1);
+ arg2 = tswap32(arg2);
+ arg3 = tswap32(arg3);
+ arg4 = tswap32(arg4);
+ arg5 = tswap32(arg5);
+ arg6 = tswap32(arg6);
+ arg7 = tswap32(arg7);
+ arg8 = tswap32(arg8);
+
+ num = num-COMMPAGE_START-2;
+
+ for(i = 0; i < sizeof(commpage_entries)/sizeof(commpage_entries[0]); i++) {
+ if( num == commpage_code_num(&commpage_entries[i]) )
+ {
+ DPRINTF("commpage: %s %s\n", commpage_entries[i].name, commpage_is_indirect(&commpage_entries[i]) ? "[indirect]" : "[direct]");
+ found = 1;
+ if(commpage_is_indirect(&commpage_entries[i]))
+ {
+ commpage_indirect_function_t function = (commpage_indirect_function_t)commpage_entries[i].function;
+ function(cpu_env, num, arg1, arg2, arg3,
+ arg4, arg5, arg6, arg7, arg8);
+ }
+ else
+ {
+ commpage_entries[i].function(arg1, arg2, arg3,
+ arg4, arg5, arg6, arg7, arg8);
+ }
+ break;
+ }
+ }
+
+ if(!found)
+ {
+ gemu_log("qemu: commpage function 0x%x not defined\n", num);
+ gdb_handlesig (cpu_env, SIGTRAP);
+ exit(-1);
+ }
+}
Added: trunk/src/host/qemu-neo1973/darwin-user/ioctls.h
===================================================================
--- trunk/src/host/qemu-neo1973/darwin-user/ioctls.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/darwin-user/ioctls.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,4 @@
+ /* emulated ioctl list */
+
+ IOCTL(TIOCGETA, IOC_R, MK_PTR(MK_STRUCT(STRUCT_termios)))
+ IOCTL(TIOCSETA, IOC_W, MK_PTR(MK_STRUCT(STRUCT_termios)))
Added: trunk/src/host/qemu-neo1973/darwin-user/ioctls_types.h
===================================================================
--- trunk/src/host/qemu-neo1973/darwin-user/ioctls_types.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/darwin-user/ioctls_types.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1 @@
+STRUCT(termios, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, MK_ARRAY(TYPE_CHAR, 20), TYPE_INT, TYPE_INT)
\ No newline at end of file
Added: trunk/src/host/qemu-neo1973/darwin-user/machload.c
===================================================================
--- trunk/src/host/qemu-neo1973/darwin-user/machload.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/darwin-user/machload.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,903 @@
+/*
+ * Mach-O object file loading
+ *
+ * Copyright (c) 2006 Pierre d'Herbemont
+ *
+ * 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 <stdio.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "qemu.h"
+#include "disas.h"
+
+#include <mach-o/loader.h>
+#include <mach-o/fat.h>
+#include <mach-o/nlist.h>
+#include <mach-o/reloc.h>
+#include <mach-o/ppc/reloc.h>
+
+//#define DEBUG_MACHLOAD
+
+#ifdef DEBUG_MACHLOAD
+# define DPRINTF(...) do { if(loglevel) fprintf(logfile, __VA_ARGS__); printf(__VA_ARGS__); } while(0)
+#else
+# define DPRINTF(...) do { if(loglevel) fprintf(logfile, __VA_ARGS__); } while(0)
+#endif
+
+# define check_mach_header(x) (x.magic == MH_CIGAM)
+
+extern const char *interp_prefix;
+
+/* we don't have a good implementation for this */
+#define DONT_USE_DYLD_SHARED_MAP
+
+/* Pass extra arg to DYLD for debug */
+//#define ACTIVATE_DYLD_TRACE
+
+//#define OVERRIDE_DYLINKER
+
+#ifdef OVERRIDE_DYLINKER
+# ifdef TARGET_I386
+# define DYLINKER_NAME "/Users/steg/qemu/tests/i386-darwin-env/usr/lib/dyld"
+# else
+# define DYLINKER_NAME "/usr/lib/dyld"
+# endif
+#endif
+
+/* XXX: in an include */
+struct nlist_extended
+{
+ union {
+ char *n_name;
+ long n_strx;
+ } n_un;
+ unsigned char n_type;
+ unsigned char n_sect;
+ short st_desc;
+ unsigned long st_value;
+ unsigned long st_size;
+};
+
+/* Print symbols in gdb */
+void *macho_text_sect = 0;
+int macho_offset = 0;
+
+int load_object(const char *filename, struct target_pt_regs * regs, void ** mh);
+void qerror(const char *format, ...);
+#ifdef TARGET_I386
+typedef struct mach_i386_thread_state {
+ unsigned int eax;
+ unsigned int ebx;
+ unsigned int ecx;
+ unsigned int edx;
+ unsigned int edi;
+ unsigned int esi;
+ unsigned int ebp;
+ unsigned int esp;
+ unsigned int ss;
+ unsigned int eflags;
+ unsigned int eip;
+ unsigned int cs;
+ unsigned int ds;
+ unsigned int es;
+ unsigned int fs;
+ unsigned int gs;
+} mach_i386_thread_state_t;
+
+void bswap_i386_thread_state(struct mach_i386_thread_state *ts)
+{
+ bswap32s((uint32_t*)&ts->eax);
+ bswap32s((uint32_t*)&ts->ebx);
+ bswap32s((uint32_t*)&ts->ecx);
+ bswap32s((uint32_t*)&ts->edx);
+ bswap32s((uint32_t*)&ts->edi);
+ bswap32s((uint32_t*)&ts->esi);
+ bswap32s((uint32_t*)&ts->ebp);
+ bswap32s((uint32_t*)&ts->esp);
+ bswap32s((uint32_t*)&ts->ss);
+ bswap32s((uint32_t*)&ts->eflags);
+ bswap32s((uint32_t*)&ts->eip);
+ bswap32s((uint32_t*)&ts->cs);
+ bswap32s((uint32_t*)&ts->ds);
+ bswap32s((uint32_t*)&ts->es);
+ bswap32s((uint32_t*)&ts->fs);
+ bswap32s((uint32_t*)&ts->gs);
+}
+#define target_thread_state mach_i386_thread_state
+#define TARGET_CPU_TYPE CPU_TYPE_I386
+#define TARGET_CPU_NAME "i386"
+#endif
+
+#ifdef TARGET_PPC
+struct mach_ppc_thread_state {
+ unsigned int srr0; /* Instruction address register (PC) */
+ unsigned int srr1; /* Machine state register (supervisor) */
+ unsigned int r0;
+ unsigned int r1;
+ unsigned int r2;
+ unsigned int r3;
+ unsigned int r4;
+ unsigned int r5;
+ unsigned int r6;
+ unsigned int r7;
+ unsigned int r8;
+ unsigned int r9;
+ unsigned int r10;
+ unsigned int r11;
+ unsigned int r12;
+ unsigned int r13;
+ unsigned int r14;
+ unsigned int r15;
+ unsigned int r16;
+ unsigned int r17;
+ unsigned int r18;
+ unsigned int r19;
+ unsigned int r20;
+ unsigned int r21;
+ unsigned int r22;
+ unsigned int r23;
+ unsigned int r24;
+ unsigned int r25;
+ unsigned int r26;
+ unsigned int r27;
+ unsigned int r28;
+ unsigned int r29;
+ unsigned int r30;
+ unsigned int r31;
+
+ unsigned int cr; /* Condition register */
+ unsigned int xer; /* User's integer exception register */
+ unsigned int lr; /* Link register */
+ unsigned int ctr; /* Count register */
+ unsigned int mq; /* MQ register (601 only) */
+
+ unsigned int vrsave; /* Vector Save Register */
+};
+
+void bswap_ppc_thread_state(struct mach_ppc_thread_state *ts)
+{
+ bswap32s((uint32_t*)&ts->srr0);
+ bswap32s((uint32_t*)&ts->srr1);
+ bswap32s((uint32_t*)&ts->r0);
+ bswap32s((uint32_t*)&ts->r1);
+ bswap32s((uint32_t*)&ts->r2);
+ bswap32s((uint32_t*)&ts->r3);
+ bswap32s((uint32_t*)&ts->r4);
+ bswap32s((uint32_t*)&ts->r5);
+ bswap32s((uint32_t*)&ts->r6);
+ bswap32s((uint32_t*)&ts->r7);
+ bswap32s((uint32_t*)&ts->r8);
+ bswap32s((uint32_t*)&ts->r9);
+ bswap32s((uint32_t*)&ts->r10);
+ bswap32s((uint32_t*)&ts->r11);
+ bswap32s((uint32_t*)&ts->r12);
+ bswap32s((uint32_t*)&ts->r13);
+ bswap32s((uint32_t*)&ts->r14);
+ bswap32s((uint32_t*)&ts->r15);
+ bswap32s((uint32_t*)&ts->r16);
+ bswap32s((uint32_t*)&ts->r17);
+ bswap32s((uint32_t*)&ts->r18);
+ bswap32s((uint32_t*)&ts->r19);
+ bswap32s((uint32_t*)&ts->r20);
+ bswap32s((uint32_t*)&ts->r21);
+ bswap32s((uint32_t*)&ts->r22);
+ bswap32s((uint32_t*)&ts->r23);
+ bswap32s((uint32_t*)&ts->r24);
+ bswap32s((uint32_t*)&ts->r25);
+ bswap32s((uint32_t*)&ts->r26);
+ bswap32s((uint32_t*)&ts->r27);
+ bswap32s((uint32_t*)&ts->r28);
+ bswap32s((uint32_t*)&ts->r29);
+ bswap32s((uint32_t*)&ts->r30);
+ bswap32s((uint32_t*)&ts->r31);
+
+ bswap32s((uint32_t*)&ts->cr);
+ bswap32s((uint32_t*)&ts->xer);
+ bswap32s((uint32_t*)&ts->lr);
+ bswap32s((uint32_t*)&ts->ctr);
+ bswap32s((uint32_t*)&ts->mq);
+
+ bswap32s((uint32_t*)&ts->vrsave);
+}
+
+#define target_thread_state mach_ppc_thread_state
+#define TARGET_CPU_TYPE CPU_TYPE_POWERPC
+#define TARGET_CPU_NAME "PowerPC"
+#endif
+
+struct target_thread_command {
+ unsigned long cmd; /* LC_THREAD or LC_UNIXTHREAD */
+ unsigned long cmdsize; /* total size of this command */
+ unsigned long flavor; /* flavor of thread state */
+ unsigned long count; /* count of longs in thread state */
+ struct target_thread_state state; /* thread state for this flavor */
+};
+
+void bswap_tc(struct target_thread_command *tc)
+{
+ bswap32s((uint32_t*)(&tc->flavor));
+ bswap32s((uint32_t*)&tc->count);
+#if defined(TARGET_I386)
+ bswap_i386_thread_state(&tc->state);
+#elif defined(TARGET_PPC)
+ bswap_ppc_thread_state(&tc->state);
+#else
+# error unknown TARGET_CPU_TYPE
+#endif
+}
+
+void bswap_mh(struct mach_header *mh)
+{
+ bswap32s((uint32_t*)(&mh->magic));
+ bswap32s((uint32_t*)&mh->cputype);
+ bswap32s((uint32_t*)&mh->cpusubtype);
+ bswap32s((uint32_t*)&mh->filetype);
+ bswap32s((uint32_t*)&mh->ncmds);
+ bswap32s((uint32_t*)&mh->sizeofcmds);
+ bswap32s((uint32_t*)&mh->flags);
+}
+
+void bswap_lc(struct load_command *lc)
+{
+ bswap32s((uint32_t*)&lc->cmd);
+ bswap32s((uint32_t*)&lc->cmdsize);
+}
+
+
+void bswap_fh(struct fat_header *fh)
+{
+ bswap32s((uint32_t*)&fh->magic);
+ bswap32s((uint32_t*)&fh->nfat_arch);
+}
+
+void bswap_fa(struct fat_arch *fa)
+{
+ bswap32s((uint32_t*)&fa->cputype);
+ bswap32s((uint32_t*)&fa->cpusubtype);
+ bswap32s((uint32_t*)&fa->offset);
+ bswap32s((uint32_t*)&fa->size);
+ bswap32s((uint32_t*)&fa->align);
+}
+
+void bswap_segcmd(struct segment_command *sc)
+{
+ bswap32s((uint32_t*)&sc->vmaddr);
+ bswap32s((uint32_t*)&sc->vmsize);
+ bswap32s((uint32_t*)&sc->fileoff);
+ bswap32s((uint32_t*)&sc->filesize);
+ bswap32s((uint32_t*)&sc->maxprot);
+ bswap32s((uint32_t*)&sc->initprot);
+ bswap32s((uint32_t*)&sc->nsects);
+ bswap32s((uint32_t*)&sc->flags);
+}
+
+void bswap_symtabcmd(struct symtab_command *stc)
+{
+ bswap32s((uint32_t*)&stc->cmd);
+ bswap32s((uint32_t*)&stc->cmdsize);
+ bswap32s((uint32_t*)&stc->symoff);
+ bswap32s((uint32_t*)&stc->nsyms);
+ bswap32s((uint32_t*)&stc->stroff);
+ bswap32s((uint32_t*)&stc->strsize);
+}
+
+void bswap_sym(struct nlist *n)
+{
+ bswap32s((uint32_t*)&n->n_un.n_strx);
+ bswap16s((uint16_t*)&n->n_desc);
+ bswap32s((uint32_t*)&n->n_value);
+}
+
+int load_thread(struct mach_header *mh, struct target_thread_command *tc, struct target_pt_regs * regs, int fd, int mh_pos, int need_bswap)
+{
+ int entry;
+ if(need_bswap)
+ bswap_tc(tc);
+#if defined(TARGET_I386)
+ entry = tc->state.eip;
+ DPRINTF(" eax 0x%.8x\n ebx 0x%.8x\n ecx 0x%.8x\n edx 0x%.8x\n edi 0x%.8x\n esi 0x%.8x\n ebp 0x%.8x\n esp 0x%.8x\n ss 0x%.8x\n eflags 0x%.8x\n eip 0x%.8x\n cs 0x%.8x\n ds 0x%.8x\n es 0x%.8x\n fs 0x%.8x\n gs 0x%.8x\n",
+ tc->state.eax, tc->state.ebx, tc->state.ecx, tc->state.edx, tc->state.edi, tc->state.esi, tc->state.ebp,
+ tc->state.esp, tc->state.ss, tc->state.eflags, tc->state.eip, tc->state.cs, tc->state.ds, tc->state.es,
+ tc->state.fs, tc->state.gs );
+#define reg_copy(reg) regs->reg = tc->state.reg
+ if(regs)
+ {
+ reg_copy(eax);
+ reg_copy(ebx);
+ reg_copy(ecx);
+ reg_copy(edx);
+
+ reg_copy(edi);
+ reg_copy(esi);
+
+ reg_copy(ebp);
+ reg_copy(esp);
+
+ reg_copy(eflags);
+ reg_copy(eip);
+ /*
+ reg_copy(ss);
+ reg_copy(cs);
+ reg_copy(ds);
+ reg_copy(es);
+ reg_copy(fs);
+ reg_copy(gs);*/
+ }
+#undef reg_copy
+#elif defined(TARGET_PPC)
+ entry = tc->state.srr0;
+#endif
+ DPRINTF("load_thread: entry 0x%x\n", entry);
+ return entry;
+}
+
+int load_dylinker(struct mach_header *mh, struct dylinker_command *dc, int fd, int mh_pos, int need_bswap)
+{
+ int size;
+ char * dylinker_name;
+ size = dc->cmdsize - sizeof(struct dylinker_command);
+
+ if(need_bswap)
+ dylinker_name = (char*)(bswap_32(dc->name.offset)+(int)dc);
+ else
+ dylinker_name = (char*)((dc->name.offset)+(int)dc);
+
+#ifdef OVERRIDE_DYLINKER
+ dylinker_name = DYLINKER_NAME;
+#else
+ if(asprintf(&dylinker_name, "%s%s", interp_prefix, dylinker_name) == -1)
+ qerror("can't allocate the new dylinker name\n");
+#endif
+
+ DPRINTF("dylinker_name %s\n", dylinker_name);
+ return load_object(dylinker_name, NULL, NULL);
+}
+
+int load_segment(struct mach_header *mh, struct segment_command *sc, int fd, int mh_pos, int need_bswap, int fixed, int slide)
+{
+ unsigned long addr = sc->vmaddr;
+ unsigned long size = sc->filesize;
+ unsigned long error = 0;
+
+ if(need_bswap)
+ bswap_segcmd(sc);
+
+ if(sc->vmaddr == 0)
+ {
+ DPRINTF("load_segment: sc->vmaddr == 0 returning\n");
+ return -1;
+ }
+
+ if (strcmp(sc->segname, "__PAGEZERO") == 0)
+ {
+ DPRINTF("load_segment: __PAGEZERO returning\n");
+ return -1;
+ }
+
+ /* Right now mmap memory */
+ /* XXX: should check to see that the space is free, because MAP_FIXED is dangerous */
+ DPRINTF("load_segment: mmaping %s to 0x%x-(0x%x|0x%x) + 0x%x\n", sc->segname, sc->vmaddr, sc->filesize, sc->vmsize, slide);
+
+ if(sc->filesize > 0)
+ {
+ int opt = 0;
+
+ if(fixed)
+ opt |= MAP_FIXED;
+
+ DPRINTF("sc->vmaddr 0x%x slide 0x%x add 0x%x\n", slide, sc->vmaddr, sc->vmaddr+slide);
+
+ addr = target_mmap(sc->vmaddr+slide, sc->filesize, sc->initprot, opt, fd, mh_pos + sc->fileoff);
+
+ if(addr==-1)
+ qerror("load_segment: can't mmap at 0x%x\n", sc->vmaddr+slide);
+
+ error = addr-sc->vmaddr;
+ }
+ else
+ {
+ addr = sc->vmaddr+slide;
+ error = slide;
+ }
+
+ if(sc->vmsize > sc->filesize)
+ {
+ addr += sc->filesize;
+ size = sc->vmsize-sc->filesize;
+ addr = target_mmap(addr, size, sc->initprot, MAP_ANONYMOUS | MAP_FIXED, -1, 0);
+ if(addr==-1)
+ qerror("load_segment: can't mmap at 0x%x\n", sc->vmaddr+slide);
+ }
+
+ return error;
+}
+
+void *load_data(int fd, long offset, unsigned int size)
+{
+ char *data;
+
+ data = malloc(size);
+ if (!data)
+ return NULL;
+ lseek(fd, offset, SEEK_SET);
+ if (read(fd, data, size) != size) {
+ free(data);
+ return NULL;
+ }
+ return data;
+}
+
+/* load a mach-o object file */
+int load_object(const char *filename, struct target_pt_regs * regs, void ** mh)
+{
+ int need_bswap = 0;
+ int entry_point = 0;
+ int dyld_entry_point = 0;
+ int slide, mmapfixed;
+ int fd;
+ struct load_command *lcmds, *lc;
+ int is_fat = 0;
+ unsigned int i, magic;
+ int mach_hdr_pos = 0;
+ struct mach_header mach_hdr;
+
+ /* for symbol lookup whith -d flag. */
+ struct symtab_command * symtabcmd = 0;
+ struct nlist_extended *symtab, *sym;
+ struct nlist *symtab_std, *syment;
+ char *strtab;
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0)
+ qerror("can't open file '%s'", filename);
+
+ /* Read magic header. */
+ if (read(fd, &magic, sizeof (magic)) != sizeof (magic))
+ qerror("unable to read Magic of '%s'", filename);
+
+ /* Check Mach identification. */
+ if(magic == MH_MAGIC)
+ {
+ is_fat = 0;
+ need_bswap = 0;
+ } else if (magic == MH_CIGAM)
+ {
+ is_fat = 0;
+ need_bswap = 1;
+ } else if (magic == FAT_MAGIC)
+ {
+ is_fat = 1;
+ need_bswap = 0;
+ } else if (magic == FAT_CIGAM)
+ {
+ is_fat = 1;
+ need_bswap = 1;
+ }
+ else
+ qerror("Not a Mach-O file.", filename);
+
+ DPRINTF("loading %s %s...\n", filename, is_fat ? "[FAT]": "[REGULAR]");
+ if(is_fat)
+ {
+ int found = 0;
+ struct fat_header fh;
+ struct fat_arch *fa;
+
+ lseek(fd, 0, SEEK_SET);
+
+ /* Read Fat header. */
+ if (read(fd, &fh, sizeof (fh)) != sizeof (fh))
+ qerror("unable to read file header");
+
+ if(need_bswap)
+ bswap_fh(&fh);
+
+ /* Read Fat Arch. */
+ fa = malloc(sizeof(struct fat_arch)*fh.nfat_arch);
+
+ if (read(fd, fa, sizeof(struct fat_arch)*fh.nfat_arch) != sizeof(struct fat_arch)*fh.nfat_arch)
+ qerror("unable to read file header");
+
+ for( i = 0; i < fh.nfat_arch; i++, fa++)
+ {
+ if(need_bswap)
+ bswap_fa(fa);
+ if(fa->cputype == TARGET_CPU_TYPE)
+ {
+ mach_hdr_pos = fa->offset;
+ lseek(fd, mach_hdr_pos, SEEK_SET);
+
+ /* Read Mach header. */
+
+ if (read(fd, &mach_hdr, sizeof(struct mach_header)) != sizeof (struct mach_header))
+ qerror("unable to read file header");
+
+ if(mach_hdr.magic == MH_MAGIC)
+ need_bswap = 0;
+ else if (mach_hdr.magic == MH_CIGAM)
+ need_bswap = 1;
+ else
+ qerror("Invalid mach header in Fat Mach-O File");
+ found = 1;
+ break;
+ }
+ }
+ if(!found)
+ qerror("%s: No %s CPU found in FAT Header", filename, TARGET_CPU_NAME);
+ }
+ else
+ {
+ lseek(fd, 0, SEEK_SET);
+ /* Read Mach header */
+ if (read(fd, &mach_hdr, sizeof (mach_hdr)) != sizeof (mach_hdr))
+ qerror("%s: unable to read file header", filename);
+ }
+
+ if(need_bswap)
+ bswap_mh(&mach_hdr);
+
+ if ((mach_hdr.cputype) != TARGET_CPU_TYPE)
+ qerror("%s: Unsupported CPU 0x%x (only 0x%x(%s) supported)", filename, mach_hdr.cputype, TARGET_CPU_TYPE, TARGET_CPU_NAME);
+
+
+ switch(mach_hdr.filetype)
+ {
+ case MH_EXECUTE: break;
+ case MH_FVMLIB:
+ case MH_DYLIB:
+ case MH_DYLINKER: break;
+ default:
+ qerror("%s: Unsupported Mach type (0x%x)", filename, mach_hdr.filetype);
+ }
+
+ /* read segment headers */
+ lcmds = malloc(mach_hdr.sizeofcmds);
+
+ if(read(fd, lcmds, mach_hdr.sizeofcmds) != mach_hdr.sizeofcmds)
+ qerror("%s: unable to read load_command", filename);
+ slide = 0;
+ mmapfixed = 0;
+ for(i=0, lc = lcmds; i < (mach_hdr.ncmds) ; i++)
+ {
+
+ if(need_bswap)
+ bswap_lc(lc);
+ switch(lc->cmd)
+ {
+ case LC_SEGMENT:
+ /* The main_exe can't be relocated */
+ if(mach_hdr.filetype == MH_EXECUTE)
+ mmapfixed = 1;
+
+ slide = load_segment(&mach_hdr, (struct segment_command*)lc, fd, mach_hdr_pos, need_bswap, mmapfixed, slide);
+
+ /* other segment must be mapped according to slide exactly, if load_segment did something */
+ if(slide != -1)
+ mmapfixed = 1;
+ else
+ slide = 0; /* load_segment didn't map the segment */
+
+ if(mach_hdr.filetype == MH_EXECUTE && slide != 0)
+ qerror("%s: Warning executable can't be mapped at the right address (offset: 0x%x)\n", filename, slide);
+
+ if(strcmp(((struct segment_command*)(lc))->segname, "__TEXT") == 0)
+ {
+ /* Text section */
+ if(mach_hdr.filetype == MH_EXECUTE)
+ {
+ /* return the mach_header */
+ *mh = (void*)(((struct segment_command*)(lc))->vmaddr + slide);
+ }
+ else
+ {
+ /* it is dyld save the section for gdb, we will be interested in dyld symbol
+ while debuging */
+ macho_text_sect = (void*)(((struct segment_command*)(lc))->vmaddr + slide);
+ macho_offset = slide;
+ }
+ }
+ break;
+ case LC_LOAD_DYLINKER:
+ dyld_entry_point = load_dylinker( &mach_hdr, (struct dylinker_command*)lc, fd, mach_hdr_pos, need_bswap );
+ break;
+ case LC_LOAD_DYLIB:
+ /* dyld will do that for us */
+ break;
+ case LC_THREAD:
+ case LC_UNIXTHREAD:
+ {
+ struct target_pt_regs * _regs;
+ if(mach_hdr.filetype == MH_DYLINKER)
+ _regs = regs;
+ else
+ _regs = 0;
+ entry_point = load_thread( &mach_hdr, (struct target_thread_command*)lc, _regs, fd, mach_hdr_pos, need_bswap );
+ }
+ break;
+ case LC_SYMTAB:
+ /* Save the symtab and strtab */
+ symtabcmd = (struct symtab_command *)lc;
+ break;
+ case LC_ID_DYLINKER:
+ case LC_ID_DYLIB:
+ case LC_UUID:
+ case LC_DYSYMTAB:
+ case LC_TWOLEVEL_HINTS:
+ case LC_PREBIND_CKSUM:
+ case LC_SUB_LIBRARY:
+ break;
+ default: fprintf(stderr, "warning: unkown command 0x%x in '%s'\n", lc->cmd, filename);
+ }
+ lc = (struct load_command*)((int)(lc)+(lc->cmdsize));
+ }
+
+ if(symtabcmd)
+ {
+ if(need_bswap)
+ bswap_symtabcmd(symtabcmd);
+
+ symtab_std = load_data(fd, symtabcmd->symoff+mach_hdr_pos, symtabcmd->nsyms * sizeof(struct nlist));
+ strtab = load_data(fd, symtabcmd->stroff+mach_hdr_pos, symtabcmd->strsize);
+
+ symtab = malloc(sizeof(struct nlist_extended) * symtabcmd->nsyms);
+
+ if(need_bswap)
+ {
+ for(i = 0, syment = symtab_std; i < symtabcmd->nsyms; i++, syment++)
+ bswap_sym(syment);
+ }
+
+ for(i = 0, sym = symtab, syment = symtab_std; i < symtabcmd->nsyms; i++, sym++, syment++)
+ {
+ struct nlist *sym_follow, *sym_next = 0;
+ unsigned int j;
+ memset(sym, 0, sizeof(*sym));
+
+ sym->n_type = syment->n_type;
+ if ( syment->n_type & N_STAB ) /* Debug symbols are skipped */
+ continue;
+
+ memcpy(sym, syment, sizeof(*syment));
+
+ /* Find the following symbol in order to get the current symbol size */
+ for(j = 0, sym_follow = symtab_std; j < symtabcmd->nsyms; j++, sym_follow++) {
+ if ( sym_follow->n_type & N_STAB || !(sym_follow->n_value > sym->st_value))
+ continue;
+ if(!sym_next) {
+ sym_next = sym_follow;
+ continue;
+ }
+ if(!(sym_next->n_value > sym_follow->n_value))
+ continue;
+ sym_next = sym_follow;
+ }
+ if(sym_next)
+ sym->st_size = sym_next->n_value - sym->st_value;
+ else
+ sym->st_size = 10; /* XXX: text_sec_hdr->size + text_sec_hdr->offset - sym->st_value; */
+
+ sym->st_value += slide;
+ }
+
+ free((void*)symtab_std);
+
+ {
+ DPRINTF("saving symtab of %s (%d symbol(s))\n", filename, symtabcmd->nsyms);
+ struct syminfo *s;
+ s = malloc(sizeof(*s));
+ s->disas_symtab = symtab;
+ s->disas_strtab = strtab;
+ s->disas_num_syms = symtabcmd->nsyms;
+ s->next = syminfos;
+ syminfos = s;
+ }
+ }
+ close(fd);
+ if(mach_hdr.filetype == MH_EXECUTE && dyld_entry_point)
+ return dyld_entry_point;
+ else
+ return entry_point+slide;
+}
+
+extern unsigned long stack_size;
+
+unsigned long setup_arg_pages(void * mh, char ** argv, char ** env)
+{
+ unsigned long stack_base, error, size;
+ int i;
+ int * stack;
+ int argc, envc;
+
+ /* Create enough stack to hold everything. If we don't use
+ * it for args, we'll use it for something else...
+ */
+ size = stack_size;
+
+ error = target_mmap(0,
+ size + qemu_host_page_size,
+ PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS,
+ -1, 0);
+ if (error == -1)
+ qerror("stk mmap");
+
+ /* we reserve one extra page at the top of the stack as guard */
+ target_mprotect(error + size, qemu_host_page_size, PROT_NONE);
+
+ stack_base = error + size;
+ stack = (void*)stack_base;
+/*
+ * | STRING AREA |
+ * +-------------+
+ * | 0 |
+* +-------------+
+ * | apple[n] |
+ * +-------------+
+ * :
+ * +-------------+
+ * | apple[0] |
+ * +-------------+
+ * | 0 |
+ * +-------------+
+ * | env[n] |
+ * +-------------+
+ * :
+ * :
+ * +-------------+
+ * | env[0] |
+ * +-------------+
+ * | 0 |
+ * +-------------+
+ * | arg[argc-1] |
+ * +-------------+
+ * :
+ * :
+ * +-------------+
+ * | arg[0] |
+ * +-------------+
+ * | argc |
+ * +-------------+
+ * sp-> | mh | address of where the a.out's file offset 0 is in memory
+ * +-------------+
+*/
+ /* Construct the stack Stack grows down */
+ stack--;
+
+ /* XXX: string should go up there */
+
+ *stack = 0;
+ stack--;
+
+ /* Push the absolute path of our executable */
+ DPRINTF("pushing apple %s (0x%x)\n", (char*)argv[0], (int)argv[0]);
+ stl(stack, (int) argv[0]);
+
+ stack--;
+
+ stl(stack, 0);
+ stack--;
+
+ /* Get envc */
+ for(envc = 0; env[envc]; envc++);
+
+ for(i = envc-1; i >= 0; i--)
+ {
+ DPRINTF("pushing env %s (0x%x)\n", (char*)env[i], (int)env[i]);
+ stl(stack, (int)env[i]);
+ stack--;
+
+ /* XXX: remove that when string will be on top of the stack */
+ page_set_flags((int)env[i], (int)(env[i]+strlen(env[i])), PROT_READ | PAGE_VALID);
+ }
+
+ /* Add on the stack the interp_prefix choosen if so */
+ if(interp_prefix[0])
+ {
+ char *dyld_root;
+ asprintf(&dyld_root, "DYLD_ROOT_PATH=%s", interp_prefix);
+ page_set_flags((int)dyld_root, (int)(dyld_root+strlen(interp_prefix)+1), PROT_READ | PAGE_VALID);
+
+ stl(stack, (int)dyld_root);
+ stack--;
+ }
+
+#ifdef DONT_USE_DYLD_SHARED_MAP
+ {
+ char *shared_map_mode;
+ asprintf(&shared_map_mode, "DYLD_SHARED_REGION=avoid");
+ page_set_flags((int)shared_map_mode, (int)(shared_map_mode+strlen(shared_map_mode)+1), PROT_READ | PAGE_VALID);
+
+ stl(stack, (int)shared_map_mode);
+ stack--;
+ }
+#endif
+
+#ifdef ACTIVATE_DYLD_TRACE
+ char * extra_env_static[] = {"DYLD_DEBUG_TRACE=yes",
+ "DYLD_PREBIND_DEBUG=3", "DYLD_UNKNOW_TRACE=yes",
+ "DYLD_PRINT_INITIALIZERS=yes",
+ "DYLD_PRINT_SEGMENTS=yes", "DYLD_PRINT_REBASINGS=yes", "DYLD_PRINT_BINDINGS=yes", "DYLD_PRINT_INITIALIZERS=yes", "DYLD_PRINT_WARNINGS=yes" };
+
+ char ** extra_env = malloc(sizeof(extra_env_static));
+ bcopy(extra_env_static, extra_env, sizeof(extra_env_static));
+ page_set_flags((int)extra_env, (int)((void*)extra_env+sizeof(extra_env_static)), PROT_READ | PAGE_VALID);
+
+ for(i = 0; i<9; i++)
+ {
+ DPRINTF("pushing (extra) env %s (0x%x)\n", (char*)extra_env[i], (int)extra_env[i]);
+ stl(stack, (int) extra_env[i]);
+ stack--;
+ }
+#endif
+
+ stl(stack, 0);
+ stack--;
+
+ /* Get argc */
+ for(argc = 0; argv[argc]; argc++);
+
+ for(i = argc-1; i >= 0; i--)
+ {
+ DPRINTF("pushing arg %s (0x%x)\n", (char*)argv[i], (int)argv[i]);
+ stl(stack, (int) argv[i]);
+ stack--;
+
+ /* XXX: remove that when string will be on top of the stack */
+ page_set_flags((int)argv[i], (int)(argv[i]+strlen(argv[i])), PROT_READ | PAGE_VALID);
+ }
+
+ DPRINTF("pushing argc %d \n", argc);
+ stl(stack, argc);
+ stack--;
+
+ DPRINTF("pushing mh 0x%x \n", (int)mh);
+ stl(stack, (int) mh);
+
+ /* Stack points on the mh */
+ return (unsigned long)stack;
+}
+
+int mach_exec(const char * filename, char ** argv, char ** envp,
+ struct target_pt_regs * regs)
+{
+ int entrypoint, stack;
+ void * mh; /* the Mach Header that will be used by dyld */
+
+ DPRINTF("mach_exec at 0x%x\n", (int)mach_exec);
+
+ entrypoint = load_object(filename, regs, &mh);
+ stack = setup_arg_pages(mh, argv, envp);
+#if defined(TARGET_I386)
+ regs->eip = entrypoint;
+ regs->esp = stack;
+#elif defined(TARGET_PPC)
+ regs->nip = entrypoint;
+ regs->gpr[1] = stack;
+#endif
+ DPRINTF("mach_exec returns eip set to 0x%x esp 0x%x mh 0x%x\n", entrypoint, stack, (int)mh);
+
+ if(!entrypoint)
+ qerror("%s: no entry point!\n", filename);
+
+ return 0;
+}
Added: trunk/src/host/qemu-neo1973/darwin-user/main.c
===================================================================
--- trunk/src/host/qemu-neo1973/darwin-user/main.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/darwin-user/main.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,918 @@
+/*
+ * qemu user main
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ * Copyright (c) 2006 Pierre d'Herbemont
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <sys/syscall.h>
+#include <sys/mman.h>
+
+#include "qemu.h"
+
+#define DEBUG_LOGFILE "/tmp/qemu.log"
+
+#ifdef __APPLE__
+#include <crt_externs.h>
+# define environ (*_NSGetEnviron())
+#endif
+
+#include <mach/mach_init.h>
+#include <mach/vm_map.h>
+
+const char *interp_prefix = "";
+
+asm(".zerofill __STD_PROG_ZONE, __STD_PROG_ZONE, __std_prog_zone, 0x0dfff000");
+
+/* XXX: on x86 MAP_GROWSDOWN only works if ESP <= address + 32, so
+ we allocate a bigger stack. Need a better solution, for example
+ by remapping the process stack directly at the right place */
+unsigned long stack_size = 512 * 1024;
+
+void qerror(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ fprintf(stderr, "\n");
+ exit(1);
+}
+
+void gemu_log(const char *fmt, ...)
+{
+ va_list ap;
+
+ va_start(ap, fmt);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+}
+
+void cpu_outb(CPUState *env, int addr, int val)
+{
+ fprintf(stderr, "outb: port=0x%04x, data=%02x\n", addr, val);
+}
+
+void cpu_outw(CPUState *env, int addr, int val)
+{
+ fprintf(stderr, "outw: port=0x%04x, data=%04x\n", addr, val);
+}
+
+void cpu_outl(CPUState *env, int addr, int val)
+{
+ fprintf(stderr, "outl: port=0x%04x, data=%08x\n", addr, val);
+}
+
+int cpu_inb(CPUState *env, int addr)
+{
+ fprintf(stderr, "inb: port=0x%04x\n", addr);
+ return 0;
+}
+
+int cpu_inw(CPUState *env, int addr)
+{
+ fprintf(stderr, "inw: port=0x%04x\n", addr);
+ return 0;
+}
+
+int cpu_inl(CPUState *env, int addr)
+{
+ fprintf(stderr, "inl: port=0x%04x\n", addr);
+ return 0;
+}
+
+int cpu_get_pic_interrupt(CPUState *env)
+{
+ return -1;
+}
+#ifdef TARGET_PPC
+
+static inline uint64_t cpu_ppc_get_tb (CPUState *env)
+{
+ /* TO FIX */
+ return 0;
+}
+
+uint32_t cpu_ppc_load_tbl (CPUState *env)
+{
+ return cpu_ppc_get_tb(env) & 0xFFFFFFFF;
+}
+
+uint32_t cpu_ppc_load_tbu (CPUState *env)
+{
+ return cpu_ppc_get_tb(env) >> 32;
+}
+
+static void cpu_ppc_store_tb (CPUState *env, uint64_t value)
+{
+ /* TO FIX */
+}
+
+void cpu_ppc_store_tbu (CPUState *env, uint32_t value)
+{
+ cpu_ppc_store_tb(env, ((uint64_t)value << 32) | cpu_ppc_load_tbl(env));
+}
+
+void cpu_ppc_store_tbl (CPUState *env, uint32_t value)
+{
+ cpu_ppc_store_tb(env, ((uint64_t)cpu_ppc_load_tbl(env) << 32) | value);
+}
+
+uint32_t cpu_ppc_load_decr (CPUState *env)
+{
+ /* TO FIX */
+ return -1;
+}
+
+void cpu_ppc_store_decr (CPUState *env, uint32_t value)
+{
+ /* TO FIX */
+}
+
+void cpu_loop(CPUPPCState *env)
+{
+ int trapnr;
+ uint32_t ret;
+ target_siginfo_t info;
+
+ for(;;) {
+ trapnr = cpu_ppc_exec(env);
+ if (trapnr != EXCP_SYSCALL_USER && trapnr != EXCP_BRANCH &&
+ trapnr != EXCP_TRACE) {
+ if (loglevel > 0) {
+ cpu_dump_state(env, logfile, fprintf, 0);
+ }
+ }
+ switch(trapnr) {
+ case EXCP_NONE:
+ break;
+ case EXCP_SYSCALL_USER:
+ /* system call */
+ if(((int)env->gpr[0]) <= SYS_MAXSYSCALL && ((int)env->gpr[0])>0)
+ ret = do_unix_syscall(env, env->gpr[0]/*, env->gpr[3], env->gpr[4],
+ env->gpr[5], env->gpr[6], env->gpr[7],
+ env->gpr[8], env->gpr[9], env->gpr[10]*/);
+ else if(((int)env->gpr[0])<0)
+ ret = do_mach_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4],
+ env->gpr[5], env->gpr[6], env->gpr[7],
+ env->gpr[8], env->gpr[9], env->gpr[10]);
+ else
+ ret = do_thread_syscall(env, env->gpr[0], env->gpr[3], env->gpr[4],
+ env->gpr[5], env->gpr[6], env->gpr[7],
+ env->gpr[8], env->gpr[9], env->gpr[10]);
+
+ /* Unix syscall error signaling */
+ if(((int)env->gpr[0]) <= SYS_MAXSYSCALL && ((int)env->gpr[0])>0)
+ {
+ if( (int)ret < 0 )
+ env->nip += 0;
+ else
+ env->nip += 4;
+ }
+
+ /* Return value */
+ env->gpr[3] = ret;
+ break;
+ case EXCP_RESET:
+ /* Should not happen ! */
+ fprintf(stderr, "RESET asked... Stop emulation\n");
+ if (loglevel)
+ fprintf(logfile, "RESET asked... Stop emulation\n");
+ abort();
+ case EXCP_MACHINE_CHECK:
+ fprintf(stderr, "Machine check exeption... Stop emulation\n");
+ if (loglevel)
+ fprintf(logfile, "RESET asked... Stop emulation\n");
+ info.si_signo = SIGBUS;
+ info.si_errno = 0;
+ info.si_code = BUS_OBJERR;
+ info.si_addr = (void*)(env->nip - 4);
+ queue_signal(info.si_signo, &info);
+ case EXCP_DSI:
+#ifndef DAR
+/* To deal with multiple qemu header version as host for the darwin-user code */
+# define DAR SPR_DAR
+#endif
+ fprintf(stderr, "Invalid data memory access: 0x%08x\n", env->spr[DAR]);
+ if (loglevel) {
+ fprintf(logfile, "Invalid data memory access: 0x%08x\n",
+ env->spr[DAR]);
+ }
+ /* Handle this via the gdb */
+ gdb_handlesig (env, SIGSEGV);
+
+ info.si_addr = (void*)env->nip;
+ queue_signal(info.si_signo, &info);
+ break;
+ case EXCP_ISI:
+ fprintf(stderr, "Invalid instruction fetch\n");
+ if (loglevel)
+ fprintf(logfile, "Invalid instruction fetch\n");
+ /* Handle this via the gdb */
+ gdb_handlesig (env, SIGSEGV);
+
+ info.si_addr = (void*)(env->nip - 4);
+ queue_signal(info.si_signo, &info);
+ break;
+ case EXCP_EXTERNAL:
+ /* Should not happen ! */
+ fprintf(stderr, "External interruption... Stop emulation\n");
+ if (loglevel)
+ fprintf(logfile, "External interruption... Stop emulation\n");
+ abort();
+ case EXCP_ALIGN:
+ fprintf(stderr, "Invalid unaligned memory access\n");
+ if (loglevel)
+ fprintf(logfile, "Invalid unaligned memory access\n");
+ info.si_signo = SIGBUS;
+ info.si_errno = 0;
+ info.si_code = BUS_ADRALN;
+ info.si_addr = (void*)(env->nip - 4);
+ queue_signal(info.si_signo, &info);
+ break;
+ case EXCP_PROGRAM:
+ switch (env->error_code & ~0xF) {
+ case EXCP_FP:
+ fprintf(stderr, "Program exception\n");
+ if (loglevel)
+ fprintf(logfile, "Program exception\n");
+ /* Set FX */
+ env->fpscr[7] |= 0x8;
+ /* Finally, update FEX */
+ if ((((env->fpscr[7] & 0x3) << 3) | (env->fpscr[6] >> 1)) &
+ ((env->fpscr[1] << 1) | (env->fpscr[0] >> 3)))
+ env->fpscr[7] |= 0x4;
+ info.si_signo = SIGFPE;
+ info.si_errno = 0;
+ switch (env->error_code & 0xF) {
+ case EXCP_FP_OX:
+ info.si_code = FPE_FLTOVF;
+ break;
+ case EXCP_FP_UX:
+ info.si_code = FPE_FLTUND;
+ break;
+ case EXCP_FP_ZX:
+ case EXCP_FP_VXZDZ:
+ info.si_code = FPE_FLTDIV;
+ break;
+ case EXCP_FP_XX:
+ info.si_code = FPE_FLTRES;
+ break;
+ case EXCP_FP_VXSOFT:
+ info.si_code = FPE_FLTINV;
+ break;
+ case EXCP_FP_VXNAN:
+ case EXCP_FP_VXISI:
+ case EXCP_FP_VXIDI:
+ case EXCP_FP_VXIMZ:
+ case EXCP_FP_VXVC:
+ case EXCP_FP_VXSQRT:
+ case EXCP_FP_VXCVI:
+ info.si_code = FPE_FLTSUB;
+ break;
+ default:
+ fprintf(stderr, "Unknown floating point exception "
+ "(%02x)\n", env->error_code);
+ if (loglevel) {
+ fprintf(logfile, "Unknown floating point exception "
+ "(%02x)\n", env->error_code & 0xF);
+ }
+ }
+ break;
+ case EXCP_INVAL:
+ fprintf(stderr, "Invalid instruction\n");
+ if (loglevel)
+ fprintf(logfile, "Invalid instruction\n");
+ info.si_signo = SIGILL;
+ info.si_errno = 0;
+ switch (env->error_code & 0xF) {
+ case EXCP_INVAL_INVAL:
+ info.si_code = ILL_ILLOPC;
+ break;
+ case EXCP_INVAL_LSWX:
+ info.si_code = ILL_ILLOPN;
+ break;
+ case EXCP_INVAL_SPR:
+ info.si_code = ILL_PRVREG;
+ break;
+ case EXCP_INVAL_FP:
+ info.si_code = ILL_COPROC;
+ break;
+ default:
+ fprintf(stderr, "Unknown invalid operation (%02x)\n",
+ env->error_code & 0xF);
+ if (loglevel) {
+ fprintf(logfile, "Unknown invalid operation (%02x)\n",
+ env->error_code & 0xF);
+ }
+ info.si_code = ILL_ILLADR;
+ break;
+ }
+ /* Handle this via the gdb */
+ gdb_handlesig (env, SIGSEGV);
+ break;
+ case EXCP_PRIV:
+ fprintf(stderr, "Privilege violation\n");
+ if (loglevel)
+ fprintf(logfile, "Privilege violation\n");
+ info.si_signo = SIGILL;
+ info.si_errno = 0;
+ switch (env->error_code & 0xF) {
+ case EXCP_PRIV_OPC:
+ info.si_code = ILL_PRVOPC;
+ break;
+ case EXCP_PRIV_REG:
+ info.si_code = ILL_PRVREG;
+ break;
+ default:
+ fprintf(stderr, "Unknown privilege violation (%02x)\n",
+ env->error_code & 0xF);
+ info.si_code = ILL_PRVOPC;
+ break;
+ }
+ break;
+ case EXCP_TRAP:
+ fprintf(stderr, "Tried to call a TRAP\n");
+ if (loglevel)
+ fprintf(logfile, "Tried to call a TRAP\n");
+ abort();
+ default:
+ /* Should not happen ! */
+ fprintf(stderr, "Unknown program exception (%02x)\n",
+ env->error_code);
+ if (loglevel) {
+ fprintf(logfile, "Unknwon program exception (%02x)\n",
+ env->error_code);
+ }
+ abort();
+ }
+ info.si_addr = (void*)(env->nip - 4);
+ queue_signal(info.si_signo, &info);
+ break;
+ case EXCP_NO_FP:
+ fprintf(stderr, "No floating point allowed\n");
+ if (loglevel)
+ fprintf(logfile, "No floating point allowed\n");
+ info.si_signo = SIGILL;
+ info.si_errno = 0;
+ info.si_code = ILL_COPROC;
+ info.si_addr = (void*)(env->nip - 4);
+ queue_signal(info.si_signo, &info);
+ break;
+ case EXCP_DECR:
+ /* Should not happen ! */
+ fprintf(stderr, "Decrementer exception\n");
+ if (loglevel)
+ fprintf(logfile, "Decrementer exception\n");
+ abort();
+ case EXCP_TRACE:
+ /* Pass to gdb: we use this to trace execution */
+ gdb_handlesig (env, SIGTRAP);
+ break;
+ case EXCP_FP_ASSIST:
+ /* Should not happen ! */
+ fprintf(stderr, "Floating point assist exception\n");
+ if (loglevel)
+ fprintf(logfile, "Floating point assist exception\n");
+ abort();
+ case EXCP_MTMSR:
+ /* We reloaded the msr, just go on */
+ if (msr_pr == 0) {
+ fprintf(stderr, "Tried to go into supervisor mode !\n");
+ if (loglevel)
+ fprintf(logfile, "Tried to go into supervisor mode !\n");
+ abort();
+ }
+ break;
+ case EXCP_BRANCH:
+ /* We stopped because of a jump... */
+ break;
+ case EXCP_INTERRUPT:
+ /* Don't know why this should ever happen... */
+ fprintf(stderr, "EXCP_INTERRUPT\n");
+ break;
+ case EXCP_DEBUG:
+ gdb_handlesig (env, SIGTRAP);
+ break;
+ default:
+ fprintf(stderr, "qemu: unhandled CPU exception 0x%x - aborting\n",
+ trapnr);
+ if (loglevel) {
+ fprintf(logfile, "qemu: unhandled CPU exception 0x%02x - "
+ "0x%02x - aborting\n", trapnr, env->error_code);
+ }
+ abort();
+ }
+ process_pending_signals(env);
+ }
+}
+#endif
+
+
+#ifdef TARGET_I386
+
+/***********************************************************/
+/* CPUX86 core interface */
+
+uint64_t cpu_get_tsc(CPUX86State *env)
+{
+ return cpu_get_real_ticks();
+}
+
+void
+write_dt(void *ptr, unsigned long addr, unsigned long limit,
+ int flags)
+{
+ unsigned int e1, e2;
+ e1 = (addr << 16) | (limit & 0xffff);
+ e2 = ((addr >> 16) & 0xff) | (addr & 0xff000000) | (limit & 0x000f0000);
+ e2 |= flags;
+ stl((uint8_t *)ptr, e1);
+ stl((uint8_t *)ptr + 4, e2);
+}
+
+static void set_gate(void *ptr, unsigned int type, unsigned int dpl,
+ unsigned long addr, unsigned int sel)
+{
+ unsigned int e1, e2;
+ e1 = (addr & 0xffff) | (sel << 16);
+ e2 = (addr & 0xffff0000) | 0x8000 | (dpl << 13) | (type << 8);
+ stl((uint8_t *)ptr, e1);
+ stl((uint8_t *)ptr + 4, e2);
+}
+
+#define GDT_TABLE_SIZE 14
+#define LDT_TABLE_SIZE 15
+#define IDT_TABLE_SIZE 256
+#define TSS_SIZE 104
+uint64_t gdt_table[GDT_TABLE_SIZE];
+uint64_t ldt_table[LDT_TABLE_SIZE];
+uint64_t idt_table[IDT_TABLE_SIZE];
+uint32_t tss[TSS_SIZE];
+
+/* only dpl matters as we do only user space emulation */
+static void set_idt(int n, unsigned int dpl)
+{
+ set_gate(idt_table + n, 0, dpl, 0, 0);
+}
+
+/* ABI convention: after a syscall if there was an error the CF flag is set */
+static inline void set_error(CPUX86State *env, int ret)
+{
+ if(ret<0)
+ env->eflags = env->eflags | 0x1;
+ else
+ env->eflags &= ~0x1;
+ env->regs[R_EAX] = ret;
+}
+
+void cpu_loop(CPUX86State *env)
+{
+ int trapnr;
+ int ret;
+ uint8_t *pc;
+ target_siginfo_t info;
+
+ for(;;) {
+ trapnr = cpu_x86_exec(env);
+ uint32_t *params = (uint32_t *)env->regs[R_ESP];
+ switch(trapnr) {
+ case 0x79: /* Our commpage hack back door exit is here */
+ do_commpage(env, env->eip, *(params + 1), *(params + 2),
+ *(params + 3), *(params + 4),
+ *(params + 5), *(params + 6),
+ *(params + 7), *(params + 8));
+ break;
+ case 0x81: /* mach syscall */
+ {
+ ret = do_mach_syscall(env, env->regs[R_EAX],
+ *(params + 1), *(params + 2),
+ *(params + 3), *(params + 4),
+ *(params + 5), *(params + 6),
+ *(params + 7), *(params + 8));
+ set_error(env, ret);
+ break;
+ }
+ case 0x90: /* unix backdoor */
+ {
+ /* after sysenter, stack is in R_ECX, new eip in R_EDX (sysexit will flip them back)*/
+ int saved_stack = env->regs[R_ESP];
+ env->regs[R_ESP] = env->regs[R_ECX];
+
+ ret = do_unix_syscall(env, env->regs[R_EAX]);
+
+ env->regs[R_ECX] = env->regs[R_ESP];
+ env->regs[R_ESP] = saved_stack;
+
+ set_error(env, ret);
+ break;
+ }
+ case 0x80: /* unix syscall */
+ {
+ ret = do_unix_syscall(env, env->regs[R_EAX]/*,
+ *(params + 1), *(params + 2),
+ *(params + 3), *(params + 4),
+ *(params + 5), *(params + 6),
+ *(params + 7), *(params + 8)*/);
+ set_error(env, ret);
+ break;
+ }
+ case 0x82: /* thread syscall */
+ {
+ ret = do_thread_syscall(env, env->regs[R_EAX],
+ *(params + 1), *(params + 2),
+ *(params + 3), *(params + 4),
+ *(params + 5), *(params + 6),
+ *(params + 7), *(params + 8));
+ set_error(env, ret);
+ break;
+ }
+ case EXCP0B_NOSEG:
+ case EXCP0C_STACK:
+ info.si_signo = SIGBUS;
+ info.si_errno = 0;
+ info.si_code = BUS_NOOP;
+ info.si_addr = 0;
+ gdb_handlesig (env, SIGBUS);
+ queue_signal(info.si_signo, &info);
+ break;
+ case EXCP0D_GPF:
+ info.si_signo = SIGSEGV;
+ info.si_errno = 0;
+ info.si_code = SEGV_NOOP;
+ info.si_addr = 0;
+ gdb_handlesig (env, SIGSEGV);
+ queue_signal(info.si_signo, &info);
+ break;
+ case EXCP0E_PAGE:
+ info.si_signo = SIGSEGV;
+ info.si_errno = 0;
+ if (!(env->error_code & 1))
+ info.si_code = SEGV_MAPERR;
+ else
+ info.si_code = SEGV_ACCERR;
+ info.si_addr = (void*)env->cr[2];
+ gdb_handlesig (env, SIGSEGV);
+ queue_signal(info.si_signo, &info);
+ break;
+ case EXCP00_DIVZ:
+ /* division by zero */
+ info.si_signo = SIGFPE;
+ info.si_errno = 0;
+ info.si_code = FPE_INTDIV;
+ info.si_addr = (void*)env->eip;
+ gdb_handlesig (env, SIGFPE);
+ queue_signal(info.si_signo, &info);
+ break;
+ case EXCP01_SSTP:
+ case EXCP03_INT3:
+ info.si_signo = SIGTRAP;
+ info.si_errno = 0;
+ info.si_code = TRAP_BRKPT;
+ info.si_addr = (void*)env->eip;
+ gdb_handlesig (env, SIGTRAP);
+ queue_signal(info.si_signo, &info);
+ break;
+ case EXCP04_INTO:
+ case EXCP05_BOUND:
+ info.si_signo = SIGSEGV;
+ info.si_errno = 0;
+ info.si_code = SEGV_NOOP;
+ info.si_addr = 0;
+ gdb_handlesig (env, SIGSEGV);
+ queue_signal(info.si_signo, &info);
+ break;
+ case EXCP06_ILLOP:
+ info.si_signo = SIGILL;
+ info.si_errno = 0;
+ info.si_code = ILL_ILLOPN;
+ info.si_addr = (void*)env->eip;
+ gdb_handlesig (env, SIGILL);
+ queue_signal(info.si_signo, &info);
+ break;
+ case EXCP_INTERRUPT:
+ /* just indicate that signals should be handled asap */
+ break;
+ case EXCP_DEBUG:
+ {
+ int sig;
+
+ sig = gdb_handlesig (env, SIGTRAP);
+ if (sig)
+ {
+ info.si_signo = sig;
+ info.si_errno = 0;
+ info.si_code = TRAP_BRKPT;
+ queue_signal(info.si_signo, &info);
+ }
+ }
+ break;
+ default:
+ pc = (void*)(env->segs[R_CS].base + env->eip);
+ fprintf(stderr, "qemu: 0x%08lx: unhandled CPU exception 0x%x - aborting\n",
+ (long)pc, trapnr);
+ abort();
+ }
+ process_pending_signals(env);
+ }
+}
+#endif
+
+void usage(void)
+{
+ printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003-2004 Fabrice Bellard\n"
+ "usage: qemu-" TARGET_ARCH " [-h] [-d opts] [-L path] [-s size] program [arguments...]\n"
+ "Darwin CPU emulator (compiled for %s emulation)\n"
+ "\n"
+ "-h print this help\n"
+ "-L path set the %s library path (default='%s')\n"
+ "-s size set the stack size in bytes (default=%ld)\n"
+ "\n"
+ "debug options:\n"
+#ifdef USE_CODE_COPY
+ "-no-code-copy disable code copy acceleration\n"
+#endif
+ "-d options activate log (logfile='%s')\n"
+ "-g wait for gdb on port 1234\n"
+ "-p pagesize set the host page size to 'pagesize'\n",
+ TARGET_ARCH,
+ TARGET_ARCH,
+ interp_prefix,
+ stack_size,
+ DEBUG_LOGFILE);
+ _exit(1);
+}
+
+/* XXX: currently only used for async signals (see signal.c) */
+CPUState *global_env;
+/* used only if single thread */
+CPUState *cpu_single_env = NULL;
+
+/* used to free thread contexts */
+TaskState *first_task_state;
+
+int main(int argc, char **argv)
+{
+ const char *filename;
+ struct target_pt_regs regs1, *regs = ®s1;
+ TaskState ts1, *ts = &ts1;
+ CPUState *env;
+ int optind;
+ short use_gdbstub = 0;
+ const char *r;
+
+ if (argc <= 1)
+ usage();
+
+ /* init debug */
+ cpu_set_log_filename(DEBUG_LOGFILE);
+
+ optind = 1;
+ for(;;) {
+ if (optind >= argc)
+ break;
+ r = argv[optind];
+ if (r[0] != '-')
+ break;
+ optind++;
+ r++;
+ if (!strcmp(r, "-")) {
+ break;
+ } else if (!strcmp(r, "d")) {
+ int mask;
+ CPULogItem *item;
+
+ if (optind >= argc)
+ break;
+
+ r = argv[optind++];
+ mask = cpu_str_to_log_mask(r);
+ if (!mask) {
+ printf("Log items (comma separated):\n");
+ for(item = cpu_log_items; item->mask != 0; item++) {
+ printf("%-10s %s\n", item->name, item->help);
+ }
+ exit(1);
+ }
+ cpu_set_log(mask);
+ } else if (!strcmp(r, "s")) {
+ r = argv[optind++];
+ stack_size = strtol(r, (char **)&r, 0);
+ if (stack_size <= 0)
+ usage();
+ if (*r == 'M')
+ stack_size *= 1024 * 1024;
+ else if (*r == 'k' || *r == 'K')
+ stack_size *= 1024;
+ } else if (!strcmp(r, "L")) {
+ interp_prefix = argv[optind++];
+ } else if (!strcmp(r, "p")) {
+ qemu_host_page_size = atoi(argv[optind++]);
+ if (qemu_host_page_size == 0 ||
+ (qemu_host_page_size & (qemu_host_page_size - 1)) != 0) {
+ fprintf(stderr, "page size must be a power of two\n");
+ exit(1);
+ }
+ } else
+ if (!strcmp(r, "g")) {
+ use_gdbstub = 1;
+ } else
+#ifdef USE_CODE_COPY
+ if (!strcmp(r, "no-code-copy")) {
+ code_copy_enabled = 0;
+ } else
+#endif
+ {
+ usage();
+ }
+ }
+ if (optind >= argc)
+ usage();
+ filename = argv[optind];
+
+ /* Zero out regs */
+ memset(regs, 0, sizeof(struct target_pt_regs));
+
+ /* NOTE: we need to init the CPU at this stage to get
+ qemu_host_page_size */
+ env = cpu_init();
+
+ printf("Starting %s with qemu\n----------------\n", filename);
+
+ commpage_init();
+
+ if (mach_exec(filename, argv+optind, environ, regs) != 0) {
+ printf("Error loading %s\n", filename);
+ _exit(1);
+ }
+
+ syscall_init();
+ signal_init();
+ global_env = env;
+
+ /* build Task State */
+ memset(ts, 0, sizeof(TaskState));
+ env->opaque = ts;
+ ts->used = 1;
+ env->user_mode_only = 1;
+
+#if defined(TARGET_I386)
+ cpu_x86_set_cpl(env, 3);
+
+ env->cr[0] = CR0_PG_MASK | CR0_WP_MASK | CR0_PE_MASK;
+ env->hflags |= HF_PE_MASK;
+
+ if (env->cpuid_features & CPUID_SSE) {
+ env->cr[4] |= CR4_OSFXSR_MASK;
+ env->hflags |= HF_OSFXSR_MASK;
+ }
+
+ /* flags setup : we activate the IRQs by default as in user mode */
+ env->eflags |= IF_MASK;
+
+ /* darwin register setup */
+ env->regs[R_EAX] = regs->eax;
+ env->regs[R_EBX] = regs->ebx;
+ env->regs[R_ECX] = regs->ecx;
+ env->regs[R_EDX] = regs->edx;
+ env->regs[R_ESI] = regs->esi;
+ env->regs[R_EDI] = regs->edi;
+ env->regs[R_EBP] = regs->ebp;
+ env->regs[R_ESP] = regs->esp;
+ env->eip = regs->eip;
+
+ /* Darwin LDT setup */
+ /* 2 - User code segment
+ 3 - User data segment
+ 4 - User cthread */
+ bzero(ldt_table, LDT_TABLE_SIZE * sizeof(ldt_table[0]));
+ env->ldt.base = (uint32_t) ldt_table;
+ env->ldt.limit = sizeof(ldt_table) - 1;
+
+ write_dt(ldt_table + 2, 0, 0xfffff,
+ DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
+ (3 << DESC_DPL_SHIFT) | (0xa << DESC_TYPE_SHIFT));
+ write_dt(ldt_table + 3, 0, 0xfffff,
+ DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
+ (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT));
+ write_dt(ldt_table + 4, 0, 0xfffff,
+ DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
+ (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT));
+
+ /* Darwin GDT setup.
+ * has changed a lot between old Darwin/x86 (pre-Mac Intel) and Mac OS X/x86,
+ now everything is done via int 0x81(mach) int 0x82 (thread) and sysenter/sysexit(unix) */
+ bzero(gdt_table, sizeof(gdt_table));
+ env->gdt.base = (uint32_t)gdt_table;
+ env->gdt.limit = sizeof(gdt_table) - 1;
+
+ /* Set up a back door to handle sysenter syscalls (unix) */
+ char * syscallbackdoor = malloc(64);
+ page_set_flags((int)syscallbackdoor, (int)syscallbackdoor + 64, PROT_EXEC | PROT_READ | PAGE_VALID);
+
+ int i = 0;
+ syscallbackdoor[i++] = 0xcd;
+ syscallbackdoor[i++] = 0x90; /* int 0x90 */
+ syscallbackdoor[i++] = 0x0F;
+ syscallbackdoor[i++] = 0x35; /* sysexit */
+
+ /* Darwin sysenter/sysexit setup */
+ env->sysenter_cs = 0x1; //XXX
+ env->sysenter_eip = (int)syscallbackdoor;
+ env->sysenter_esp = (int)malloc(64);
+
+ /* Darwin TSS setup
+ This must match up with GDT[4] */
+ env->tr.base = (uint32_t) tss;
+ env->tr.limit = sizeof(tss) - 1;
+ env->tr.flags = DESC_P_MASK | (0x9 << DESC_TYPE_SHIFT);
+ stw(tss + 2, 0x10); // ss0 = 0x10 = GDT[2] = Kernel Data Segment
+
+ /* Darwin interrupt setup */
+ bzero(idt_table, sizeof(idt_table));
+ env->idt.base = (uint32_t) idt_table;
+ env->idt.limit = sizeof(idt_table) - 1;
+ set_idt(0, 0);
+ set_idt(1, 0);
+ set_idt(2, 0);
+ set_idt(3, 3);
+ set_idt(4, 3);
+ set_idt(5, 3);
+ set_idt(6, 0);
+ set_idt(7, 0);
+ set_idt(8, 0);
+ set_idt(9, 0);
+ set_idt(10, 0);
+ set_idt(11, 0);
+ set_idt(12, 0);
+ set_idt(13, 0);
+ set_idt(14, 0);
+ set_idt(15, 0);
+ set_idt(16, 0);
+ set_idt(17, 0);
+ set_idt(18, 0);
+ set_idt(19, 0);
+ /* Syscalls are done via
+ int 0x80 (unix) (rarely used)
+ int 0x81 (mach)
+ int 0x82 (thread)
+ int 0x83 (diag) (not handled here)
+ sysenter/sysexit (unix) -> we redirect that to int 0x90 */
+ set_idt(0x79, 3); /* Commpage hack, here is our backdoor interrupt */
+ set_idt(0x80, 3); /* Unix Syscall */
+ set_idt(0x81, 3); /* Mach Syscalls */
+ set_idt(0x82, 3); /* thread Syscalls */
+
+ set_idt(0x90, 3); /* qemu-darwin-user's Unix syscalls backdoor */
+
+
+ cpu_x86_load_seg(env, R_CS, __USER_CS);
+ cpu_x86_load_seg(env, R_DS, __USER_DS);
+ cpu_x86_load_seg(env, R_ES, __USER_DS);
+ cpu_x86_load_seg(env, R_SS, __USER_DS);
+ cpu_x86_load_seg(env, R_FS, __USER_DS);
+ cpu_x86_load_seg(env, R_GS, __USER_DS);
+
+#elif defined(TARGET_PPC)
+ {
+ int i;
+ env->nip = regs->nip;
+ for(i = 0; i < 32; i++) {
+ env->gpr[i] = regs->gpr[i];
+ }
+ }
+#else
+#error unsupported target CPU
+#endif
+
+ if (use_gdbstub) {
+ printf("Waiting for gdb Connection on port 1234...\n");
+ gdbserver_start (1234);
+ gdb_handlesig(env, 0);
+ }
+
+ cpu_loop(env);
+ /* never exits */
+ return 0;
+}
Added: trunk/src/host/qemu-neo1973/darwin-user/mmap.c
===================================================================
--- trunk/src/host/qemu-neo1973/darwin-user/mmap.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/darwin-user/mmap.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,411 @@
+/*
+ * mmap support for qemu
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/mman.h>
+
+#include "qemu.h"
+
+//#define DEBUG_MMAP
+
+/* NOTE: all the constants are the HOST ones */
+int target_mprotect(unsigned long start, unsigned long len, int prot)
+{
+ unsigned long end, host_start, host_end, addr;
+ int prot1, ret;
+
+#ifdef DEBUG_MMAP
+ printf("mprotect: start=0x%lx len=0x%lx prot=%c%c%c\n", start, len,
+ prot & PROT_READ ? 'r' : '-',
+ prot & PROT_WRITE ? 'w' : '-',
+ prot & PROT_EXEC ? 'x' : '-');
+#endif
+
+ if ((start & ~TARGET_PAGE_MASK) != 0)
+ return -EINVAL;
+ len = TARGET_PAGE_ALIGN(len);
+ end = start + len;
+ if (end < start)
+ return -EINVAL;
+ if (prot & ~(PROT_READ | PROT_WRITE | PROT_EXEC))
+ return -EINVAL;
+ if (len == 0)
+ return 0;
+
+ host_start = start & qemu_host_page_mask;
+ host_end = HOST_PAGE_ALIGN(end);
+ if (start > host_start) {
+ /* handle host page containing start */
+ prot1 = prot;
+ for(addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) {
+ prot1 |= page_get_flags(addr);
+ }
+ if (host_end == host_start + qemu_host_page_size) {
+ for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
+ prot1 |= page_get_flags(addr);
+ }
+ end = host_end;
+ }
+ ret = mprotect((void *)host_start, qemu_host_page_size, prot1 & PAGE_BITS);
+ if (ret != 0)
+ return ret;
+ host_start += qemu_host_page_size;
+ }
+ if (end < host_end) {
+ prot1 = prot;
+ for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
+ prot1 |= page_get_flags(addr);
+ }
+ ret = mprotect((void *)(host_end - qemu_host_page_size), qemu_host_page_size,
+ prot1 & PAGE_BITS);
+ if (ret != 0)
+ return ret;
+ host_end -= qemu_host_page_size;
+ }
+
+ /* handle the pages in the middle */
+ if (host_start < host_end) {
+ ret = mprotect((void *)host_start, host_end - host_start, prot);
+ if (ret != 0)
+ return ret;
+ }
+ page_set_flags(start, start + len, prot | PAGE_VALID);
+ return 0;
+}
+
+/* map an incomplete host page */
+int mmap_frag(unsigned long host_start,
+ unsigned long start, unsigned long end,
+ int prot, int flags, int fd, unsigned long offset)
+{
+ unsigned long host_end, ret, addr;
+ int prot1, prot_new;
+
+ host_end = host_start + qemu_host_page_size;
+
+ /* get the protection of the target pages outside the mapping */
+ prot1 = 0;
+ for(addr = host_start; addr < host_end; addr++) {
+ if (addr < start || addr >= end)
+ prot1 |= page_get_flags(addr);
+ }
+
+ if (prot1 == 0) {
+ /* no page was there, so we allocate one */
+ ret = (long)mmap((void *)host_start, qemu_host_page_size, prot,
+ flags | MAP_ANONYMOUS, -1, 0);
+ if (ret == -1)
+ return ret;
+ }
+ prot1 &= PAGE_BITS;
+
+ prot_new = prot | prot1;
+ if (!(flags & MAP_ANONYMOUS)) {
+ /* msync() won't work here, so we return an error if write is
+ possible while it is a shared mapping */
+#ifndef __APPLE__
+ if ((flags & MAP_TYPE) == MAP_SHARED &&
+#else
+ if ((flags & MAP_SHARED) &&
+#endif
+ (prot & PROT_WRITE))
+ return -EINVAL;
+
+ /* adjust protection to be able to read */
+ if (!(prot1 & PROT_WRITE))
+ mprotect((void *)host_start, qemu_host_page_size, prot1 | PROT_WRITE);
+
+ /* read the corresponding file data */
+ pread(fd, (void *)start, end - start, offset);
+
+ /* put final protection */
+ if (prot_new != (prot1 | PROT_WRITE))
+ mprotect((void *)host_start, qemu_host_page_size, prot_new);
+ } else {
+ /* just update the protection */
+ if (prot_new != prot1) {
+ mprotect((void *)host_start, qemu_host_page_size, prot_new);
+ }
+ }
+ return 0;
+}
+
+/* NOTE: all the constants are the HOST ones */
+long target_mmap(unsigned long start, unsigned long len, int prot,
+ int flags, int fd, unsigned long offset)
+{
+ unsigned long ret, end, host_start, host_end, retaddr, host_offset, host_len;
+#if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__)
+ static unsigned long last_start = 0x40000000;
+#endif
+
+#ifdef DEBUG_MMAP
+ {
+ printf("mmap: start=0x%lx len=0x%lx prot=%c%c%c flags=",
+ start, len,
+ prot & PROT_READ ? 'r' : '-',
+ prot & PROT_WRITE ? 'w' : '-',
+ prot & PROT_EXEC ? 'x' : '-');
+ if (flags & MAP_FIXED)
+ printf("MAP_FIXED ");
+ if (flags & MAP_ANONYMOUS)
+ printf("MAP_ANON ");
+#ifndef MAP_TYPE
+# define MAP_TYPE 0x3
+#endif
+ switch(flags & MAP_TYPE) {
+ case MAP_PRIVATE:
+ printf("MAP_PRIVATE ");
+ break;
+ case MAP_SHARED:
+ printf("MAP_SHARED ");
+ break;
+ default:
+ printf("[MAP_TYPE=0x%x] ", flags & MAP_TYPE);
+ break;
+ }
+ printf("fd=%d offset=%lx\n", fd, offset);
+ }
+#endif
+
+ if (offset & ~TARGET_PAGE_MASK)
+ return -EINVAL;
+
+ len = TARGET_PAGE_ALIGN(len);
+ if (len == 0)
+ return start;
+ host_start = start & qemu_host_page_mask;
+
+ if (!(flags & MAP_FIXED)) {
+#if defined(__alpha__) || defined(__sparc__) || defined(__x86_64__)
+ /* tell the kenel to search at the same place as i386 */
+ if (host_start == 0) {
+ host_start = last_start;
+ last_start += HOST_PAGE_ALIGN(len);
+ }
+#endif
+ if (qemu_host_page_size != qemu_real_host_page_size) {
+ /* NOTE: this code is only for debugging with '-p' option */
+ /* reserve a memory area */
+ host_len = HOST_PAGE_ALIGN(len) + qemu_host_page_size - TARGET_PAGE_SIZE;
+ host_start = (long)mmap((void *)host_start, host_len, PROT_NONE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ if (host_start == -1)
+ return host_start;
+ host_end = host_start + host_len;
+ start = HOST_PAGE_ALIGN(host_start);
+ end = start + HOST_PAGE_ALIGN(len);
+ if (start > host_start)
+ munmap((void *)host_start, start - host_start);
+ if (end < host_end)
+ munmap((void *)end, host_end - end);
+ /* use it as a fixed mapping */
+ flags |= MAP_FIXED;
+ } else {
+ /* if not fixed, no need to do anything */
+ host_offset = offset & qemu_host_page_mask;
+ host_len = len + offset - host_offset;
+ start = (long)mmap((void *)host_start, host_len,
+ prot, flags, fd, host_offset);
+ if (start == -1)
+ return start;
+ /* update start so that it points to the file position at 'offset' */
+ if (!(flags & MAP_ANONYMOUS))
+ start += offset - host_offset;
+ goto the_end1;
+ }
+ }
+
+ if (start & ~TARGET_PAGE_MASK)
+ return -EINVAL;
+ end = start + len;
+ host_end = HOST_PAGE_ALIGN(end);
+
+ /* worst case: we cannot map the file because the offset is not
+ aligned, so we read it */
+ if (!(flags & MAP_ANONYMOUS) &&
+ (offset & ~qemu_host_page_mask) != (start & ~qemu_host_page_mask)) {
+ /* msync() won't work here, so we return an error if write is
+ possible while it is a shared mapping */
+#ifndef __APPLE__
+ if ((flags & MAP_TYPE) == MAP_SHARED &&
+#else
+ if ((flags & MAP_SHARED) &&
+#endif
+ (prot & PROT_WRITE))
+ return -EINVAL;
+ retaddr = target_mmap(start, len, prot | PROT_WRITE,
+ MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS,
+ -1, 0);
+ if (retaddr == -1)
+ return retaddr;
+ pread(fd, (void *)start, len, offset);
+ if (!(prot & PROT_WRITE)) {
+ ret = target_mprotect(start, len, prot);
+ if (ret != 0)
+ return ret;
+ }
+ goto the_end;
+ }
+
+ /* handle the start of the mapping */
+ if (start > host_start) {
+ if (host_end == host_start + qemu_host_page_size) {
+ /* one single host page */
+ ret = mmap_frag(host_start, start, end,
+ prot, flags, fd, offset);
+ if (ret == -1)
+ return ret;
+ goto the_end1;
+ }
+ ret = mmap_frag(host_start, start, host_start + qemu_host_page_size,
+ prot, flags, fd, offset);
+ if (ret == -1)
+ return ret;
+ host_start += qemu_host_page_size;
+ }
+ /* handle the end of the mapping */
+ if (end < host_end) {
+ ret = mmap_frag(host_end - qemu_host_page_size,
+ host_end - qemu_host_page_size, host_end,
+ prot, flags, fd,
+ offset + host_end - qemu_host_page_size - start);
+ if (ret == -1)
+ return ret;
+ host_end -= qemu_host_page_size;
+ }
+
+ /* map the middle (easier) */
+ if (host_start < host_end) {
+ unsigned long offset1;
+ if (flags & MAP_ANONYMOUS)
+ offset1 = 0;
+ else
+ offset1 = offset + host_start - start;
+ ret = (long)mmap((void *)host_start, host_end - host_start,
+ prot, flags, fd, offset1);
+ if (ret == -1)
+ return ret;
+ }
+ the_end1:
+ page_set_flags(start, start + len, prot | PAGE_VALID);
+ the_end:
+#ifdef DEBUG_MMAP
+ printf("target_mmap: ret=0x%lx\n", (long)start);
+ page_dump(stdout);
+ printf("\n");
+#endif
+ return start;
+}
+
+int target_munmap(unsigned long start, unsigned long len)
+{
+ unsigned long end, host_start, host_end, addr;
+ int prot, ret;
+
+#ifdef DEBUG_MMAP
+ printf("munmap: start=0x%lx len=0x%lx\n", start, len);
+#endif
+ if (start & ~TARGET_PAGE_MASK)
+ return -EINVAL;
+ len = TARGET_PAGE_ALIGN(len);
+ if (len == 0)
+ return -EINVAL;
+ end = start + len;
+ host_start = start & qemu_host_page_mask;
+ host_end = HOST_PAGE_ALIGN(end);
+
+ if (start > host_start) {
+ /* handle host page containing start */
+ prot = 0;
+ for(addr = host_start; addr < start; addr += TARGET_PAGE_SIZE) {
+ prot |= page_get_flags(addr);
+ }
+ if (host_end == host_start + qemu_host_page_size) {
+ for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
+ prot |= page_get_flags(addr);
+ }
+ end = host_end;
+ }
+ if (prot != 0)
+ host_start += qemu_host_page_size;
+ }
+ if (end < host_end) {
+ prot = 0;
+ for(addr = end; addr < host_end; addr += TARGET_PAGE_SIZE) {
+ prot |= page_get_flags(addr);
+ }
+ if (prot != 0)
+ host_end -= qemu_host_page_size;
+ }
+
+ /* unmap what we can */
+ if (host_start < host_end) {
+ ret = munmap((void *)host_start, host_end - host_start);
+ if (ret != 0)
+ return ret;
+ }
+
+ page_set_flags(start, start + len, 0);
+ return 0;
+}
+
+/* XXX: currently, we only handle MAP_ANONYMOUS and not MAP_FIXED
+ blocks which have been allocated starting on a host page */
+long target_mremap(unsigned long old_addr, unsigned long old_size,
+ unsigned long new_size, unsigned long flags,
+ unsigned long new_addr)
+{
+#ifndef __APPLE__
+ /* XXX: use 5 args syscall */
+ new_addr = (long)mremap((void *)old_addr, old_size, new_size, flags);
+ if (new_addr == -1)
+ return new_addr;
+ prot = page_get_flags(old_addr);
+ page_set_flags(old_addr, old_addr + old_size, 0);
+ page_set_flags(new_addr, new_addr + new_size, prot | PAGE_VALID);
+ return new_addr;
+#else
+ qerror("target_mremap: unsupported\n");
+#endif
+
+}
+
+int target_msync(unsigned long start, unsigned long len, int flags)
+{
+ unsigned long end;
+
+ if (start & ~TARGET_PAGE_MASK)
+ return -EINVAL;
+ len = TARGET_PAGE_ALIGN(len);
+ end = start + len;
+ if (end < start)
+ return -EINVAL;
+ if (end == start)
+ return 0;
+
+ start &= qemu_host_page_mask;
+ return msync((void *)start, end - start, flags);
+}
+
Added: trunk/src/host/qemu-neo1973/darwin-user/qemu.h
===================================================================
--- trunk/src/host/qemu-neo1973/darwin-user/qemu.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/darwin-user/qemu.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,179 @@
+#ifndef GEMU_H
+#define GEMU_H
+
+#include "thunk.h"
+
+#include <signal.h>
+#include <string.h>
+
+#include "cpu.h"
+
+#include "gdbstub.h"
+
+typedef siginfo_t target_siginfo_t;
+#define target_sigaction sigaction
+#ifdef TARGET_I386
+struct target_pt_regs {
+ long ebx;
+ long ecx;
+ long edx;
+ long esi;
+ long edi;
+ long ebp;
+ long eax;
+ int xds;
+ int xes;
+ long orig_eax;
+ long eip;
+ int xcs;
+ long eflags;
+ long esp;
+ int xss;
+};
+struct target_sigcontext {
+ int sc_onstack;
+ int sc_mask;
+ int sc_eax;
+ int sc_ebx;
+ int sc_ecx;
+ int sc_edx;
+ int sc_edi;
+ int sc_esi;
+ int sc_ebp;
+ int sc_esp;
+ int sc_ss;
+ int sc_eflags;
+ int sc_eip;
+ int sc_cs;
+ int sc_ds;
+ int sc_es;
+ int sc_fs;
+ int sc_gs;
+};
+
+#define __USER_CS (0x17)
+#define __USER_DS (0x1F)
+
+#elif defined(TARGET_PPC)
+struct target_pt_regs {
+ unsigned long gpr[32];
+ unsigned long nip;
+ unsigned long msr;
+ unsigned long orig_gpr3; /* Used for restarting system calls */
+ unsigned long ctr;
+ unsigned long link;
+ unsigned long xer;
+ unsigned long ccr;
+ unsigned long mq; /* 601 only (not used at present) */
+ /* Used on APUS to hold IPL value. */
+ unsigned long trap; /* Reason for being here */
+ unsigned long dar; /* Fault registers */
+ unsigned long dsisr;
+ unsigned long result; /* Result of a system call */
+};
+
+struct target_sigcontext {
+ int sc_onstack; /* sigstack state to restore */
+ int sc_mask; /* signal mask to restore */
+ int sc_ir; /* pc */
+ int sc_psw; /* processor status word */
+ int sc_sp; /* stack pointer if sc_regs == NULL */
+ void *sc_regs; /* (kernel private) saved state */
+};
+
+#endif
+
+typedef struct TaskState {
+ struct TaskState *next;
+ int used; /* non zero if used */
+ uint8_t stack[0];
+} __attribute__((aligned(16))) TaskState;
+
+void syscall_init(void);
+long do_mach_syscall(void *cpu_env, int num, uint32_t arg1, uint32_t arg2, uint32_t arg3,
+ uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7, uint32_t arg8);
+long do_thread_syscall(void *cpu_env, int num, uint32_t arg1, uint32_t arg2, uint32_t arg3,
+ uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7, uint32_t arg8);
+long do_unix_syscall(void *cpu_env, int num);
+int do_sigaction(int sig, const struct sigaction *act,
+ struct sigaction *oact);
+int do_sigaltstack(const struct sigaltstack *ss, struct sigaltstack *oss);
+
+void gemu_log(const char *fmt, ...) __attribute__((format(printf,1,2)));
+void qerror(const char *fmt, ...);
+
+void write_dt(void *ptr, unsigned long addr, unsigned long limit, int flags);
+
+extern CPUState *global_env;
+void cpu_loop(CPUState *env);
+void init_paths(const char *prefix);
+const char *path(const char *pathname);
+
+extern int loglevel;
+extern FILE *logfile;
+
+/* commpage.c */
+void commpage_init();
+void do_commpage(void *cpu_env, int num, uint32_t arg1, uint32_t arg2, uint32_t arg3,
+ uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7, uint32_t arg8);
+
+/* signal.c */
+void process_pending_signals(void *cpu_env);
+void signal_init(void);
+int queue_signal(int sig, target_siginfo_t *info);
+void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info);
+void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo);
+long do_sigreturn(CPUState *env, int num);
+
+/* machload.c */
+int mach_exec(const char * filename, char ** argv, char ** envp,
+ struct target_pt_regs * regs);
+
+/* mmap.c */
+int target_mprotect(unsigned long start, unsigned long len, int prot);
+long target_mmap(unsigned long start, unsigned long len, int prot,
+ int flags, int fd, unsigned long offset);
+int target_munmap(unsigned long start, unsigned long len);
+long target_mremap(unsigned long old_addr, unsigned long old_size,
+ unsigned long new_size, unsigned long flags,
+ unsigned long new_addr);
+int target_msync(unsigned long start, unsigned long len, int flags);
+
+/* user access */
+
+/* XXX: todo protect every memory access */
+#define lock_user(x,y,z) (void*)(x)
+#define unlock_user(x,y,z)
+
+/* Mac OS X ABI arguments processing */
+#ifdef TARGET_I386
+static inline uint32_t get_int_arg(int *i, CPUX86State *cpu_env)
+{
+ uint32_t *args = (uint32_t*)(cpu_env->regs[R_ESP] + 4 + *i);
+ *i+=4;
+ return tswap32(*args);
+}
+static inline uint64_t get_int64_arg(int *i, CPUX86State *cpu_env)
+{
+ uint64_t *args = (uint64_t*)(cpu_env->regs[R_ESP] + 4 + *i);
+ *i+=8;
+ return tswap64(*args);
+}
+#elif defined(TARGET_PPC)
+static inline uint32_t get_int_arg(int *i, CPUPPCState *cpu_env)
+{
+ /* XXX: won't work when args goes on stack after gpr10 */
+ uint32_t args = (uint32_t)(cpu_env->gpr[3+(*i & 0xff)/4]);
+ *i+=4;
+ return tswap32(args);
+}
+static inline uint64_t get_int64_arg(int *i, CPUPPCState *cpu_env)
+{
+ /* XXX: won't work when args goes on stack after gpr10 */
+ uint64_t args = (uint64_t)(cpu_env->fpr[1+(*i >> 8)/8]);
+ *i+=(8 << 8) + 8;
+ return tswap64(args);
+}
+#endif
+
+#endif
Added: trunk/src/host/qemu-neo1973/darwin-user/signal.c
===================================================================
--- trunk/src/host/qemu-neo1973/darwin-user/signal.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/darwin-user/signal.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,463 @@
+/*
+ * Emulation of Linux signals
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <signal.h>
+#include <errno.h>
+#include <sys/ucontext.h>
+
+#ifdef __ia64__
+#undef uc_mcontext
+#undef uc_sigmask
+#undef uc_stack
+#undef uc_link
+#endif
+
+#include <signal.h>
+
+#include "qemu.h"
+
+#define DEBUG_SIGNAL
+
+#define MAX_SIGQUEUE_SIZE 1024
+
+struct sigqueue {
+ struct sigqueue *next;
+ target_siginfo_t info;
+};
+
+struct emulated_sigaction {
+ struct target_sigaction sa;
+ int pending; /* true if signal is pending */
+ struct sigqueue *first;
+ struct sigqueue info; /* in order to always have memory for the
+ first signal, we put it here */
+};
+
+struct sigaltstack target_sigaltstack_used = {
+ 0, 0, SA_DISABLE
+};
+
+static struct emulated_sigaction sigact_table[NSIG];
+static struct sigqueue sigqueue_table[MAX_SIGQUEUE_SIZE]; /* siginfo queue */
+static struct sigqueue *first_free; /* first free siginfo queue entry */
+static int signal_pending; /* non zero if a signal may be pending */
+
+static void host_signal_handler(int host_signum, siginfo_t *info,
+ void *puc);
+
+
+static inline int host_to_target_signal(int sig)
+{
+ return sig;
+}
+
+static inline int target_to_host_signal(int sig)
+{
+ return sig;
+}
+
+/* siginfo conversion */
+
+
+
+void host_to_target_siginfo(target_siginfo_t *tinfo, const siginfo_t *info)
+{
+
+}
+
+void target_to_host_siginfo(siginfo_t *info, const target_siginfo_t *tinfo)
+{
+
+}
+
+void signal_init(void)
+{
+ struct sigaction act;
+ int i;
+
+ /* set all host signal handlers. ALL signals are blocked during
+ the handlers to serialize them. */
+ sigfillset(&act.sa_mask);
+ act.sa_flags = SA_SIGINFO;
+ act.sa_sigaction = host_signal_handler;
+ for(i = 1; i < NSIG; i++) {
+ sigaction(i, &act, NULL);
+ }
+
+ memset(sigact_table, 0, sizeof(sigact_table));
+
+ first_free = &sigqueue_table[0];
+ for(i = 0; i < MAX_SIGQUEUE_SIZE - 1; i++)
+ sigqueue_table[i].next = &sigqueue_table[i + 1];
+ sigqueue_table[MAX_SIGQUEUE_SIZE - 1].next = NULL;
+}
+
+/* signal queue handling */
+
+static inline struct sigqueue *alloc_sigqueue(void)
+{
+ struct sigqueue *q = first_free;
+ if (!q)
+ return NULL;
+ first_free = q->next;
+ return q;
+}
+
+static inline void free_sigqueue(struct sigqueue *q)
+{
+ q->next = first_free;
+ first_free = q;
+}
+
+/* abort execution with signal */
+void __attribute((noreturn)) force_sig(int sig)
+{
+ int host_sig;
+ host_sig = target_to_host_signal(sig);
+ fprintf(stderr, "qemu: uncaught target signal %d (%s) - exiting\n",
+ sig, strsignal(host_sig));
+ _exit(-host_sig);
+}
+
+/* queue a signal so that it will be send to the virtual CPU as soon
+ as possible */
+int queue_signal(int sig, target_siginfo_t *info)
+{
+ struct emulated_sigaction *k;
+ struct sigqueue *q, **pq;
+ target_ulong handler;
+
+#if defined(DEBUG_SIGNAL)
+ fprintf(stderr, "queue_signal: sig=%d\n",
+ sig);
+#endif
+ k = &sigact_table[sig - 1];
+ handler = (target_ulong)k->sa.sa_handler;
+ if (handler == SIG_DFL) {
+ /* default handler : ignore some signal. The other are fatal */
+ if (sig != SIGCHLD &&
+ sig != SIGURG &&
+ sig != SIGWINCH) {
+ force_sig(sig);
+ } else {
+ return 0; /* indicate ignored */
+ }
+ } else if (handler == host_to_target_signal(SIG_IGN)) {
+ /* ignore signal */
+ return 0;
+ } else if (handler == host_to_target_signal(SIG_ERR)) {
+ force_sig(sig);
+ } else {
+ pq = &k->first;
+ if (!k->pending) {
+ /* first signal */
+ q = &k->info;
+ } else {
+ q = alloc_sigqueue();
+ if (!q)
+ return -EAGAIN;
+ while (*pq != NULL)
+ pq = &(*pq)->next;
+ }
+ *pq = q;
+ q->info = *info;
+ q->next = NULL;
+ k->pending = 1;
+ /* signal that a new signal is pending */
+ signal_pending = 1;
+ return 1; /* indicates that the signal was queued */
+ }
+}
+
+static void host_signal_handler(int host_signum, siginfo_t *info,
+ void *puc)
+{
+ int sig;
+ target_siginfo_t tinfo;
+
+ /* the CPU emulator uses some host signals to detect exceptions,
+ we we forward to it some signals */
+ if (host_signum == SIGSEGV || host_signum == SIGBUS
+#if defined(TARGET_I386) && defined(USE_CODE_COPY)
+ || host_signum == SIGFPE
+#endif
+ ) {
+ if (cpu_signal_handler(host_signum, (void*)info, puc))
+ return;
+ }
+
+ /* get target signal number */
+ sig = host_to_target_signal(host_signum);
+ if (sig < 1 || sig > NSIG)
+ return;
+
+#if defined(DEBUG_SIGNAL)
+ fprintf(stderr, "qemu: got signal %d\n", sig);
+#endif
+ if (queue_signal(sig, &tinfo) == 1) {
+ /* interrupt the virtual CPU as soon as possible */
+ cpu_interrupt(global_env, CPU_INTERRUPT_EXIT);
+ }
+}
+
+int do_sigaltstack(const struct sigaltstack *ss, struct sigaltstack *oss)
+{
+ /* XXX: test errors */
+ if(oss)
+ {
+ oss->ss_sp = tswap32(target_sigaltstack_used.ss_sp);
+ oss->ss_size = tswap32(target_sigaltstack_used.ss_size);
+ oss->ss_flags = tswap32(target_sigaltstack_used.ss_flags);
+ }
+ if(ss)
+ {
+ target_sigaltstack_used.ss_sp = tswap32(ss->ss_sp);
+ target_sigaltstack_used.ss_size = tswap32(ss->ss_size);
+ target_sigaltstack_used.ss_flags = tswap32(ss->ss_flags);
+ }
+ return 0;
+}
+
+int do_sigaction(int sig, const struct sigaction *act,
+ struct sigaction *oact)
+{
+ struct emulated_sigaction *k;
+ struct sigaction act1;
+ int host_sig;
+
+ if (sig < 1 || sig > NSIG)
+ return -EINVAL;
+
+ k = &sigact_table[sig - 1];
+#if defined(DEBUG_SIGNAL)
+ fprintf(stderr, "sigaction 1 sig=%d act=0x%08x, oact=0x%08x\n",
+ sig, (int)act, (int)oact);
+#endif
+ if (oact) {
+#if defined(DEBUG_SIGNAL)
+ fprintf(stderr, "sigaction 1 sig=%d act=0x%08x, oact=0x%08x\n",
+ sig, (int)act, (int)oact);
+#endif
+
+ oact->sa_handler = tswapl(k->sa.sa_handler);
+ oact->sa_flags = tswapl(k->sa.sa_flags);
+ oact->sa_mask = tswapl(k->sa.sa_mask);
+ }
+ if (act) {
+#if defined(DEBUG_SIGNAL)
+ fprintf(stderr, "sigaction handler 0x%x flag 0x%x mask 0x%x\n",
+ act->sa_handler, act->sa_flags, act->sa_mask);
+#endif
+
+ k->sa.sa_handler = tswapl(act->sa_handler);
+ k->sa.sa_flags = tswapl(act->sa_flags);
+ k->sa.sa_mask = tswapl(act->sa_mask);
+ /* we update the host signal state */
+ host_sig = target_to_host_signal(sig);
+ if (host_sig != SIGSEGV && host_sig != SIGBUS) {
+#if defined(DEBUG_SIGNAL)
+ fprintf(stderr, "sigaction handler going to call sigaction\n",
+ act->sa_handler, act->sa_flags, act->sa_mask);
+#endif
+
+ sigfillset(&act1.sa_mask);
+ act1.sa_flags = SA_SIGINFO;
+ if (k->sa.sa_flags & SA_RESTART)
+ act1.sa_flags |= SA_RESTART;
+ /* NOTE: it is important to update the host kernel signal
+ ignore state to avoid getting unexpected interrupted
+ syscalls */
+ if (k->sa.sa_handler == SIG_IGN) {
+ act1.sa_sigaction = (void *)SIG_IGN;
+ } else if (k->sa.sa_handler == SIG_DFL) {
+ act1.sa_sigaction = (void *)SIG_DFL;
+ } else {
+ act1.sa_sigaction = host_signal_handler;
+ }
+ sigaction(host_sig, &act1, NULL);
+ }
+ }
+ return 0;
+}
+
+
+#ifdef TARGET_I386
+
+static inline void *
+get_sigframe(struct emulated_sigaction *ka, CPUX86State *env, size_t frame_size)
+{
+ /* XXX Fix that */
+ if(target_sigaltstack_used.ss_flags & SA_DISABLE)
+ {
+ int esp;
+ /* Default to using normal stack */
+ esp = env->regs[R_ESP];
+
+ return (void *)((esp - frame_size) & -8ul);
+ }
+ else
+ {
+ return target_sigaltstack_used.ss_sp;
+ }
+}
+
+static void setup_frame(int sig, struct emulated_sigaction *ka,
+ void *set, CPUState *env)
+{
+ void *frame;
+ int i, err = 0;
+
+ fprintf(stderr, "setup_frame %d\n", sig);
+ frame = get_sigframe(ka, env, sizeof(*frame));
+
+ /* Set up registers for signal handler */
+ env->regs[R_ESP] = (unsigned long) frame;
+ env->eip = (unsigned long) ka->sa.sa_handler;
+
+ env->eflags &= ~TF_MASK;
+
+ return;
+
+give_sigsegv:
+ if (sig == SIGSEGV)
+ ka->sa.sa_handler = SIG_DFL;
+ force_sig(SIGSEGV /* , current */);
+}
+
+long do_sigreturn(CPUState *env, int num)
+{
+ int i = 0;
+ struct target_sigcontext *scp = get_int_arg(&i, env);
+ /* XXX Get current signal number */
+ /* XXX Adjust accordin to sc_onstack, sc_mask */
+ if(tswapl(scp->sc_onstack) & 0x1)
+ target_sigaltstack_used.ss_flags |= ~SA_DISABLE;
+ else
+ target_sigaltstack_used.ss_flags &= SA_DISABLE;
+ int set = tswapl(scp->sc_eax);
+ sigprocmask(SIG_SETMASK, &set, NULL);
+
+ fprintf(stderr, "do_sigreturn: partially implemented %x EAX:%x EBX:%x\n", scp->sc_mask, tswapl(scp->sc_eax), tswapl(scp->sc_ebx));
+ fprintf(stderr, "ECX:%x EDX:%x EDI:%x\n", scp->sc_ecx, tswapl(scp->sc_edx), tswapl(scp->sc_edi));
+ fprintf(stderr, "EIP:%x\n", tswapl(scp->sc_eip));
+
+ env->regs[R_EAX] = tswapl(scp->sc_eax);
+ env->regs[R_EBX] = tswapl(scp->sc_ebx);
+ env->regs[R_ECX] = tswapl(scp->sc_ecx);
+ env->regs[R_EDX] = tswapl(scp->sc_edx);
+ env->regs[R_EDI] = tswapl(scp->sc_edi);
+ env->regs[R_ESI] = tswapl(scp->sc_esi);
+ env->regs[R_EBP] = tswapl(scp->sc_ebp);
+ env->regs[R_ESP] = tswapl(scp->sc_esp);
+ env->segs[R_SS].selector = (void*)tswapl(scp->sc_ss);
+ env->eflags = tswapl(scp->sc_eflags);
+ env->eip = tswapl(scp->sc_eip);
+ env->segs[R_CS].selector = (void*)tswapl(scp->sc_cs);
+ env->segs[R_DS].selector = (void*)tswapl(scp->sc_ds);
+ env->segs[R_ES].selector = (void*)tswapl(scp->sc_es);
+ env->segs[R_FS].selector = (void*)tswapl(scp->sc_fs);
+ env->segs[R_GS].selector = (void*)tswapl(scp->sc_gs);
+
+ /* Again, because our caller's caller will reset EAX */
+ return env->regs[R_EAX];
+}
+
+#else
+
+static void setup_frame(int sig, struct emulated_sigaction *ka,
+ void *set, CPUState *env)
+{
+ fprintf(stderr, "setup_frame: not implemented\n");
+}
+
+long do_sigreturn(CPUState *env, int num)
+{
+ int i = 0;
+ struct target_sigcontext *scp = get_int_arg(&i, env);
+ fprintf(stderr, "do_sigreturn: not implemented\n");
+ return -ENOSYS;
+}
+
+#endif
+
+void process_pending_signals(void *cpu_env)
+{
+ struct emulated_sigaction *k;
+ struct sigqueue *q;
+ target_ulong handler;
+ int sig;
+
+ if (!signal_pending)
+ return;
+
+ k = sigact_table;
+
+ for(sig = 1; sig <= NSIG; sig++) {
+ if (k->pending)
+ goto handle_signal;
+ k++;
+ }
+
+ /* if no signal is pending, just return */
+ signal_pending = 0;
+ return;
+handle_signal:
+ #ifdef DEBUG_SIGNAL
+ fprintf(stderr, "qemu: process signal %d\n", sig);
+ #endif
+ /* dequeue signal */
+ q = k->first;
+ k->first = q->next;
+ if (!k->first)
+ k->pending = 0;
+
+ sig = gdb_handlesig (cpu_env, sig);
+ if (!sig) {
+ fprintf (stderr, "Lost signal\n");
+ abort();
+ }
+
+ handler = k->sa.sa_handler;
+ if (handler == SIG_DFL) {
+ /* default handler : ignore some signal. The other are fatal */
+ if (sig != SIGCHLD &&
+ sig != SIGURG &&
+ sig != SIGWINCH) {
+ force_sig(sig);
+ }
+ } else if (handler == SIG_IGN) {
+ /* ignore sig */
+ } else if (handler == SIG_ERR) {
+ force_sig(sig);
+ } else {
+
+ setup_frame(sig, k, 0, cpu_env);
+ if (k->sa.sa_flags & SA_RESETHAND)
+ k->sa.sa_handler = SIG_DFL;
+ }
+ if (q != &k->info)
+ free_sigqueue(q);
+}
+
+
Added: trunk/src/host/qemu-neo1973/darwin-user/syscall.c
===================================================================
--- trunk/src/host/qemu-neo1973/darwin-user/syscall.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/darwin-user/syscall.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,1567 @@
+/*
+ * Darwin syscalls
+ *
+ * Copyright (c) 2003 Fabrice Bellard
+ * Copyright (c) 2006 Pierre d'Herbemont
+ *
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <mach/host_info.h>
+#include <mach/mach.h>
+#include <mach/mach_time.h>
+#include <mach/message.h>
+
+#include <pthread.h>
+#include <dirent.h>
+
+#include <sys/stat.h>
+#include <sys/syscall.h>
+#include <sys/sysctl.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/dirent.h>
+#include <sys/uio.h>
+#include <sys/termios.h>
+#include <sys/ptrace.h>
+#include <net/if.h>
+
+#include <sys/param.h>
+#include <sys/mount.h>
+
+#include <sys/attr.h>
+
+#include <mach/ndr.h>
+#include <mach/mig_errors.h>
+
+#include <sys/xattr.h>
+
+#include "qemu.h"
+
+//#define DEBUG_SYSCALL
+
+#ifdef DEBUG_SYSCALL
+# define DEBUG_FORCE_ENABLE_LOCAL() int __DEBUG_qemu_user_force_enable = 1
+# define DEBUG_BEGIN_ENABLE __DEBUG_qemu_user_force_enable = 1;
+# define DEBUG_END_ENABLE __DEBUG_qemu_user_force_enable = 0;
+
+# define DEBUG_DISABLE_ALL() static int __DEBUG_qemu_user_force_enable = 0
+# define DEBUG_ENABLE_ALL() static int __DEBUG_qemu_user_force_enable = 1
+ DEBUG_ENABLE_ALL();
+
+# define DPRINTF(...) do { if(loglevel) fprintf(logfile, __VA_ARGS__); \
+ if(__DEBUG_qemu_user_force_enable) fprintf(stderr, __VA_ARGS__); \
+ } while(0)
+#else
+# define DEBUG_FORCE_ENABLE_LOCAL()
+# define DEBUG_BEGIN_ENABLE
+# define DEBUG_END_ENABLE
+
+# define DPRINTF(...) do { if(loglevel) fprintf(logfile, __VA_ARGS__); } while(0)
+#endif
+
+enum {
+ bswap_out = 0,
+ bswap_in = 1
+};
+
+extern const char *interp_prefix;
+
+static inline long get_errno(long ret)
+{
+ if (ret == -1)
+ return -errno;
+ else
+ return ret;
+}
+
+static inline int is_error(long ret)
+{
+ return (unsigned long)ret >= (unsigned long)(-4096);
+}
+
+/* ------------------------------------------------------------
+ Mach syscall handling
+*/
+
+void static inline print_description_msg_header(mach_msg_header_t *hdr)
+{
+ char *name = NULL;
+ int i;
+ struct { int number; char *name; } msg_name[] =
+ {
+ /* see http://fxr.watson.org/fxr/source/compat/mach/mach_namemap.c?v=NETBSD */
+ { 200, "host_info" },
+ { 202, "host_page_size" },
+ { 206, "host_get_clock_service" },
+ { 206, "host_get_clock_service" },
+ { 206, "host_get_clock_service" },
+ { 306, "host_get_clock_service" },
+ { 3204, "mach_port_allocate" },
+ { 3206, "mach_port_deallocate" },
+ { 3404, "mach_ports_lookup" },
+ { 3409, "mach_task_get_special_port" },
+ { 3414, "mach_task_get_exception_ports" },
+ { 3418, "mach_semaphore_create" },
+ { 3504, "mach_semaphore_create" },
+ { 3509, "mach_semaphore_create" },
+ { 3518, "semaphore_create" },
+ { 3616, "thread_policy" },
+ { 3801, "vm_allocate" },
+ { 3802, "vm_deallocate" },
+ { 3802, "vm_deallocate" },
+ { 3803, "vm_protect" },
+ { 3812, "vm_map" },
+ { 4241776, "lu_message_send_id" }, /* lookupd */
+ { 4241876, "lu_message_reply_id" }, /* lookupd */
+ };
+
+ for(i = 0; i < sizeof(msg_name)/sizeof(msg_name[0]); i++) {
+ if(msg_name[i].number == hdr->msgh_id)
+ {
+ name = msg_name[i].name;
+ break;
+ }
+ }
+ if(!name)
+ DPRINTF("unknown mach msg %d 0x%x\n", hdr->msgh_id, hdr->msgh_id);
+ else
+ DPRINTF("%s\n", name);
+#if 0
+ DPRINTF("Bits: %8x\n", hdr->msgh_bits);
+ DPRINTF("Size: %8x\n", hdr->msgh_size);
+ DPRINTF("Rmte: %8x\n", hdr->msgh_remote_port);
+ DPRINTF("Locl: %8x\n", hdr->msgh_local_port);
+ DPRINTF("Rsrv: %8x\n", hdr->msgh_reserved);
+
+ DPRINTF("Id : %8x\n", hdr->msgh_id);
+
+ NDR_record_t *ndr = (NDR_record_t *)(hdr + 1);
+ DPRINTF("hdr = %p, sizeof(hdr) = %x, NDR = %p\n", hdr, (unsigned int)sizeof(mach_msg_header_t), ndr);
+ DPRINTF("%d %d %d %d %d %d %d %d\n",
+ ndr->mig_vers, ndr->if_vers, ndr->reserved1, ndr->mig_encoding,
+ ndr->int_rep, ndr->char_rep, ndr->float_rep, ndr->reserved2);
+#endif
+}
+
+static inline void print_mach_msg_return(mach_msg_return_t ret)
+{
+ int i, found = 0;
+#define MACH_MSG_RET(msg) { msg, #msg }
+ struct { int code; char *name; } msg_name[] =
+ {
+ /* ref: http://darwinsource.opendarwin.org/10.4.2/xnu-792.2.4/osfmk/man/mach_msg.html */
+ /* send message */
+ MACH_MSG_RET(MACH_SEND_MSG_TOO_SMALL),
+ MACH_MSG_RET(MACH_SEND_NO_BUFFER),
+ MACH_MSG_RET(MACH_SEND_INVALID_DATA),
+ MACH_MSG_RET(MACH_SEND_INVALID_HEADER),
+ MACH_MSG_RET(MACH_SEND_INVALID_DEST),
+ MACH_MSG_RET(MACH_SEND_INVALID_NOTIFY),
+ MACH_MSG_RET(MACH_SEND_INVALID_REPLY),
+ MACH_MSG_RET(MACH_SEND_INVALID_TRAILER),
+ MACH_MSG_RET(MACH_SEND_INVALID_MEMORY),
+ MACH_MSG_RET(MACH_SEND_INVALID_RIGHT),
+ MACH_MSG_RET(MACH_SEND_INVALID_TYPE),
+ MACH_MSG_RET(MACH_SEND_INTERRUPTED),
+ MACH_MSG_RET(MACH_SEND_TIMED_OUT),
+
+ MACH_MSG_RET(MACH_RCV_BODY_ERROR),
+ MACH_MSG_RET(MACH_RCV_HEADER_ERROR),
+
+ MACH_MSG_RET(MACH_RCV_IN_SET),
+ MACH_MSG_RET(MACH_RCV_INTERRUPTED),
+
+ MACH_MSG_RET(MACH_RCV_INVALID_DATA),
+ MACH_MSG_RET(MACH_RCV_INVALID_NAME),
+ MACH_MSG_RET(MACH_RCV_INVALID_NOTIFY),
+ MACH_MSG_RET(MACH_RCV_INVALID_TRAILER),
+ MACH_MSG_RET(MACH_RCV_INVALID_TYPE),
+
+ MACH_MSG_RET(MACH_RCV_PORT_CHANGED),
+ MACH_MSG_RET(MACH_RCV_PORT_DIED),
+
+ MACH_MSG_RET(MACH_RCV_SCATTER_SMALL),
+ MACH_MSG_RET(MACH_RCV_TIMED_OUT),
+ MACH_MSG_RET(MACH_RCV_TOO_LARGE)
+ };
+#undef MACH_MSG_RET
+
+ if( ret == MACH_MSG_SUCCESS)
+ DPRINTF("MACH_MSG_SUCCESS\n");
+ else
+ {
+ for( i = 0; i < sizeof(msg_name)/sizeof(msg_name[0]); i++) {
+ if(msg_name[i].code == ret) {
+ DPRINTF("%s\n", msg_name[i].name);
+ found = 1;
+ break;
+ }
+ }
+ if(!found)
+ qerror("unknow mach message ret code %d\n", ret);
+ }
+}
+
+static inline void swap_mach_msg_header(mach_msg_header_t *hdr)
+{
+ hdr->msgh_bits = tswap32(hdr->msgh_bits);
+ hdr->msgh_size = tswap32(hdr->msgh_size);
+ hdr->msgh_remote_port = tswap32(hdr->msgh_remote_port);
+ hdr->msgh_local_port = tswap32(hdr->msgh_local_port);
+ hdr->msgh_reserved = tswap32(hdr->msgh_reserved);
+ hdr->msgh_id = tswap32(hdr->msgh_id);
+}
+
+struct complex_msg {
+ mach_msg_header_t hdr;
+ mach_msg_body_t body;
+};
+
+static inline void swap_mach_msg_body(struct complex_msg *complex_msg, int bswap)
+{
+ mach_msg_port_descriptor_t *descr = (mach_msg_port_descriptor_t *)(complex_msg+1);
+ int i,j;
+
+ if(bswap == bswap_in)
+ tswap32s(&complex_msg->body.msgh_descriptor_count);
+
+ DPRINTF("body.msgh_descriptor_count %d\n", complex_msg->body.msgh_descriptor_count);
+
+ for(i = 0; i < complex_msg->body.msgh_descriptor_count; i++) {
+ switch(descr->type)
+ {
+ case MACH_MSG_PORT_DESCRIPTOR:
+ tswap32s(&descr->name);
+ descr++;
+ break;
+ case MACH_MSG_OOL_DESCRIPTOR:
+ {
+ mach_msg_ool_descriptor_t *ool = (void *)descr;
+ tswap32s((uint32_t *)&ool->address);
+ tswap32s(&ool->size);
+
+ descr = (mach_msg_port_descriptor_t *)(ool+1);
+ break;
+ }
+ case MACH_MSG_OOL_PORTS_DESCRIPTOR:
+ {
+ mach_msg_ool_ports_descriptor_t *ool_ports = (void *)descr;
+ mach_port_name_t * port_names;
+
+ if(bswap == bswap_in)
+ {
+ tswap32s((uint32_t *)&ool_ports->address);
+ tswap32s(&ool_ports->count);
+ }
+
+ port_names = ool_ports->address;
+
+ for(j = 0; j < ool_ports->count; j++)
+ tswap32s(&port_names[j]);
+
+ if(bswap == bswap_out)
+ {
+ tswap32s((uint32_t *)&ool_ports->address);
+ tswap32s(&ool_ports->count);
+ }
+
+ descr = (mach_msg_port_descriptor_t *)(ool_ports+1);
+ break;
+ }
+ default: qerror("unknow mach msg descriptor type %x\n", descr->type);
+ }
+ }
+ if(bswap == bswap_out)
+ tswap32s(&complex_msg->body.msgh_descriptor_count);
+}
+
+static inline void swap_mach_msg(mach_msg_header_t *hdr, int bswap)
+{
+ if (bswap == bswap_out && hdr->msgh_bits & MACH_MSGH_BITS_COMPLEX)
+ swap_mach_msg_body((struct complex_msg *)hdr, bswap);
+
+ swap_mach_msg_header(hdr);
+
+ if (bswap == bswap_in && hdr->msgh_bits & MACH_MSGH_BITS_COMPLEX)
+ swap_mach_msg_body((struct complex_msg *)hdr, bswap);
+}
+
+static inline uint32_t target_mach_msg_trap(
+ mach_msg_header_t *hdr, uint32_t options, uint32_t send_size,
+ uint32_t rcv_size, uint32_t rcv_name, uint32_t time_out, uint32_t notify)
+{
+ extern int mach_msg_trap(mach_msg_header_t *, mach_msg_option_t,
+ mach_msg_size_t, mach_msg_size_t, mach_port_t,
+ mach_msg_timeout_t, mach_port_t);
+ mach_msg_audit_trailer_t *trailer;
+ mach_msg_id_t msg_id;
+ uint32_t ret = 0;
+ int i;
+
+ swap_mach_msg(hdr, bswap_in);
+
+ msg_id = hdr->msgh_id;
+
+ print_description_msg_header(hdr);
+
+ ret = mach_msg_trap(hdr, options, send_size, rcv_size, rcv_name, time_out, notify);
+
+ print_mach_msg_return(ret);
+
+ if( (options & MACH_RCV_MSG) && (REQUESTED_TRAILER_SIZE(options) > 0) )
+ {
+ /* XXX: the kernel always return the full trailer with MACH_SEND_MSG, so we should
+ probably always bswap it */
+ /* warning: according to Mac OS X Internals (the book) msg_size might be expressed in
+ natural_t units but according to xnu/osfmk/mach/message.h: "The size of
+ the message must be specified in bytes" */
+ trailer = (mach_msg_audit_trailer_t *)((uint8_t *)hdr + hdr->msgh_size);
+ /* XXX: Should probably do that based on the option asked by the sender, but dealing
+ with kernel answer seems more sound */
+ switch(trailer->msgh_trailer_size)
+ {
+ case sizeof(mach_msg_audit_trailer_t):
+ for(i = 0; i < 8; i++)
+ tswap32s(&trailer->msgh_audit.val[i]);
+ /* Fall in mach_msg_security_trailer_t case */
+ case sizeof(mach_msg_security_trailer_t):
+ tswap32s(&trailer->msgh_sender.val[0]);
+ tswap32s(&trailer->msgh_sender.val[1]);
+ /* Fall in mach_msg_seqno_trailer_t case */
+ case sizeof(mach_msg_seqno_trailer_t):
+ tswap32s(&trailer->msgh_seqno);
+ /* Fall in mach_msg_trailer_t case */
+ case sizeof(mach_msg_trailer_t):
+ tswap32s(&trailer->msgh_trailer_type);
+ tswap32s(&trailer->msgh_trailer_size);
+ break;
+ case 0:
+ /* Safer not to byteswap, but probably wrong */
+ break;
+ default:
+ qerror("unknow trailer type given its size %d\n", trailer->msgh_trailer_size);
+ break;
+ }
+ }
+
+ /* Special message handling */
+ switch (msg_id) {
+ case 200: /* host_info */
+ {
+ mig_reply_error_t *err = (mig_reply_error_t *)hdr;
+ struct {
+ uint32_t unknow1;
+ uint32_t max_cpus;
+ uint32_t avail_cpus;
+ uint32_t memory_size;
+ uint32_t cpu_type;
+ uint32_t cpu_subtype;
+ } *data = (void *)(err+1);
+
+ DPRINTF("maxcpu = 0x%x\n", data->max_cpus);
+ DPRINTF("numcpu = 0x%x\n", data->avail_cpus);
+ DPRINTF("memsize = 0x%x\n", data->memory_size);
+
+#if defined(TARGET_I386)
+ data->cpu_type = CPU_TYPE_I386;
+ DPRINTF("cpu_type changed to 0x%x(i386)\n", data->cpu_type);
+ data->cpu_subtype = CPU_SUBTYPE_PENT;
+ DPRINTF("cpu_subtype changed to 0x%x(i386_pent)\n", data->cpu_subtype);
+#elif defined(TARGET_PPC)
+ data->cpu_type = CPU_TYPE_POWERPC;
+ DPRINTF("cpu_type changed to 0x%x(ppc)\n", data->cpu_type);
+ data->cpu_subtype = CPU_SUBTYPE_POWERPC_750;
+ DPRINTF("cpu_subtype changed to 0x%x(ppc_all)\n", data->cpu_subtype);
+#else
+# error target not supported
+#endif
+ break;
+ }
+ case 202: /* host_page_size */
+ {
+ mig_reply_error_t *err = (mig_reply_error_t *)hdr;
+ uint32_t *pagesize = (uint32_t *)(err+1);
+
+ DPRINTF("pagesize = %d\n", *pagesize);
+ break;
+ }
+ default: break;
+ }
+
+ swap_mach_msg(hdr, bswap_out);
+
+ return ret;
+}
+
+long do_mach_syscall(void *cpu_env, int num, uint32_t arg1, uint32_t arg2, uint32_t arg3,
+ uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7,
+ uint32_t arg8)
+{
+ extern uint32_t mach_reply_port();
+
+ long ret = 0;
+
+ arg1 = tswap32(arg1);
+ arg2 = tswap32(arg2);
+ arg3 = tswap32(arg3);
+ arg4 = tswap32(arg4);
+ arg5 = tswap32(arg5);
+ arg6 = tswap32(arg6);
+ arg7 = tswap32(arg7);
+ arg8 = tswap32(arg8);
+
+ DPRINTF("mach syscall %d : " , num);
+
+ switch(num) {
+ /* see xnu/osfmk/mach/syscall_sw.h */
+ case -26:
+ DPRINTF("mach_reply_port()\n");
+ ret = mach_reply_port();
+ break;
+ case -27:
+ DPRINTF("mach_thread_self()\n");
+ ret = mach_thread_self();
+ break;
+ case -28:
+ DPRINTF("mach_task_self()\n");
+ ret = mach_task_self();
+ break;
+ case -29:
+ DPRINTF("mach_host_self()\n");
+ ret = mach_host_self();
+ break;
+ case -31:
+ DPRINTF("mach_msg_trap(0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n",
+ arg1, arg2, arg3, arg4, arg5, arg6, arg7);
+ ret = target_mach_msg_trap((mach_msg_header_t *)arg1, arg2, arg3, arg4, arg5, arg6, arg7);
+ break;
+/* may need more translation if target arch is different from host */
+#if (defined(TARGET_I386) && defined(__i386__)) || (defined(TARGET_PPC) && defined(__ppc__))
+ case -33:
+ DPRINTF("semaphore_signal_trap(0x%x)\n", arg1);
+ ret = semaphore_signal_trap(arg1);
+ break;
+ case -34:
+ DPRINTF("semaphore_signal_all_trap(0x%x)\n", arg1);
+ ret = semaphore_signal_all_trap(arg1);
+ break;
+ case -35:
+ DPRINTF("semaphore_signal_thread_trap(0x%x)\n", arg1, arg2);
+ ret = semaphore_signal_thread_trap(arg1,arg2);
+ break;
+#endif
+ case -36:
+ DPRINTF("semaphore_wait_trap(0x%x)\n", arg1);
+ extern int semaphore_wait_trap(int); // XXX: is there any header for that?
+ ret = semaphore_wait_trap(arg1);
+ break;
+/* may need more translation if target arch is different from host */
+#if (defined(TARGET_I386) && defined(__i386__)) || (defined(TARGET_PPC) && defined(__ppc__))
+ case -37:
+ DPRINTF("semaphore_wait_signal_trap(0x%x, 0x%x)\n", arg1, arg2);
+ ret = semaphore_wait_signal_trap(arg1,arg2);
+ break;
+#endif
+ case -43:
+ DPRINTF("map_fd(0x%x, 0x%x, 0x%x, 0x%x, 0x%x)\n",
+ arg1, arg2, arg3, arg4, arg5);
+ ret = map_fd(arg1, arg2, (void*)arg3, arg4, arg5);
+ tswap32s((uint32_t*)arg3);
+ break;
+/* may need more translation if target arch is different from host */
+#if (defined(TARGET_I386) && defined(__i386__)) || (defined(TARGET_PPC) && defined(__ppc__))
+ case -61:
+ DPRINTF("syscall_thread_switch(0x%x, 0x%x, 0x%x)\n",
+ arg1, arg2, arg3);
+ ret = syscall_thread_switch(arg1, arg2, arg3); // just a hint to the scheduler; can drop?
+ break;
+#endif
+ case -89:
+ DPRINTF("mach_timebase_info(0x%x)\n", arg1);
+ struct mach_timebase_info info;
+ ret = mach_timebase_info(&info);
+ if(!is_error(ret))
+ {
+ struct mach_timebase_info *outInfo = (void*)arg1;
+ outInfo->numer = tswap32(info.numer);
+ outInfo->denom = tswap32(info.denom);
+ }
+ break;
+ case -90:
+ DPRINTF("mach_wait_until()\n");
+ extern int mach_wait_until(uint64_t); // XXX: is there any header for that?
+ ret = mach_wait_until(((uint64_t)arg2<<32) | (uint64_t)arg1);
+ break;
+ case -91:
+ DPRINTF("mk_timer_create()\n");
+ extern int mk_timer_create(); // XXX: is there any header for that?
+ ret = mk_timer_create();
+ break;
+ case -92:
+ DPRINTF("mk_timer_destroy()\n");
+ extern int mk_timer_destroy(int); // XXX: is there any header for that?
+ ret = mk_timer_destroy(arg1);
+ break;
+ case -93:
+ DPRINTF("mk_timer_create()\n");
+ extern int mk_timer_arm(int, uint64_t); // XXX: is there any header for that?
+ ret = mk_timer_arm(arg1, ((uint64_t)arg3<<32) | (uint64_t)arg2);
+ break;
+ case -94:
+ DPRINTF("mk_timer_cancel()\n");
+ extern int mk_timer_cancel(int, uint64_t *); // XXX: is there any header for that?
+ ret = mk_timer_cancel(arg1, (uint64_t *)arg2);
+ if((!is_error(ret)) && arg2)
+ tswap64s((uint64_t *)arg2);
+ break;
+ default:
+ gemu_log("qemu: Unsupported mach syscall: %d(0x%x)\n", num, num);
+ gdb_handlesig (cpu_env, SIGTRAP);
+ exit(0);
+ break;
+ }
+ return ret;
+}
+
+/* ------------------------------------------------------------
+ thread type syscall handling
+*/
+long do_thread_syscall(void *cpu_env, int num, uint32_t arg1, uint32_t arg2, uint32_t arg3,
+ uint32_t arg4, uint32_t arg5, uint32_t arg6, uint32_t arg7,
+ uint32_t arg8)
+{
+ extern uint32_t cthread_set_self(uint32_t);
+ extern uint32_t processor_facilities_used();
+ long ret = 0;
+
+ arg1 = tswap32(arg1);
+ arg2 = tswap32(arg2);
+ arg3 = tswap32(arg3);
+ arg4 = tswap32(arg4);
+ arg5 = tswap32(arg5);
+ arg6 = tswap32(arg6);
+ arg7 = tswap32(arg7);
+ arg8 = tswap32(arg8);
+
+ DPRINTF("thread syscall %d : " , num);
+
+ switch(num) {
+#ifdef TARGET_I386
+ case 0x3:
+#endif
+ case 0x7FF1: /* cthread_set_self */
+ DPRINTF("cthread_set_self(0x%x)\n", (unsigned int)arg1);
+ ret = cthread_set_self(arg1);
+#ifdef TARGET_I386
+ /* we need to update the LDT with the address of the thread */
+ write_dt((void *)(((CPUX86State *) cpu_env)->ldt.base + (4 * sizeof(uint64_t))), arg1, 1,
+ DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | DESC_S_MASK |
+ (3 << DESC_DPL_SHIFT) | (0x2 << DESC_TYPE_SHIFT));
+ /* New i386 convention, %gs should be set to our this LDT entry */
+ cpu_x86_load_seg(cpu_env, R_GS, 0x27);
+ /* Old i386 convention, the kernel returns the selector for the cthread (pre-10.4.8?)*/
+ ret = 0x27;
+#endif
+ break;
+ case 0x7FF2: /* Called the super-fast pthread_self handler by the apple guys */
+ DPRINTF("pthread_self()\n");
+ ret = (uint32_t)pthread_self();
+ break;
+ case 0x7FF3:
+ DPRINTF("processor_facilities_used()\n");
+#ifdef __i386__
+ qerror("processor_facilities_used: not implemented!\n");
+#else
+ ret = (uint32_t)processor_facilities_used();
+#endif
+ break;
+ default:
+ gemu_log("qemu: Unsupported thread syscall: %d(0x%x)\n", num, num);
+ gdb_handlesig (cpu_env, SIGTRAP);
+ exit(0);
+ break;
+ }
+ return ret;
+}
+
+/* ------------------------------------------------------------
+ ioctl handling
+*/
+static inline void byteswap_termios(struct termios *t)
+{
+ tswap32s((uint32_t*)&t->c_iflag);
+ tswap32s((uint32_t*)&t->c_oflag);
+ tswap32s((uint32_t*)&t->c_cflag);
+ tswap32s((uint32_t*)&t->c_lflag);
+ /* 20 (char) bytes then */
+ tswap32s((uint32_t*)&t->c_ispeed);
+ tswap32s((uint32_t*)&t->c_ospeed);
+}
+
+static inline void byteswap_winsize(struct winsize *w)
+{
+ tswap16s(&w->ws_row);
+ tswap16s(&w->ws_col);
+ tswap16s(&w->ws_xpixel);
+ tswap16s(&w->ws_ypixel);
+}
+
+#define STRUCT(name, list...) STRUCT_ ## name,
+#define STRUCT_SPECIAL(name) STRUCT_ ## name,
+enum {
+#include "ioctls_types.h"
+};
+#undef STRUCT
+#undef STRUCT_SPECIAL
+
+#define STRUCT(name, list...) const argtype struct_ ## name ## _def[] = { list, TYPE_NULL };
+#define STRUCT_SPECIAL(name)
+#include "ioctls_types.h"
+#undef STRUCT
+#undef STRUCT_SPECIAL
+
+typedef struct IOCTLEntry {
+ unsigned int target_cmd;
+ unsigned int host_cmd;
+ const char *name;
+ int access;
+ const argtype arg_type[5];
+} IOCTLEntry;
+
+#define IOC_R 0x0001
+#define IOC_W 0x0002
+#define IOC_RW (IOC_R | IOC_W)
+
+#define MAX_STRUCT_SIZE 4096
+
+IOCTLEntry ioctl_entries[] = {
+#define IOCTL(cmd, access, types...) \
+ { cmd, cmd, #cmd, access, { types } },
+#include "ioctls.h"
+ { 0, 0, },
+};
+
+/* ??? Implement proper locking for ioctls. */
+static long do_ioctl(long fd, long cmd, long arg)
+{
+ const IOCTLEntry *ie;
+ const argtype *arg_type;
+ int ret;
+ uint8_t buf_temp[MAX_STRUCT_SIZE];
+ int target_size;
+ void *argptr;
+
+ ie = ioctl_entries;
+ for(;;) {
+ if (ie->target_cmd == 0) {
+ gemu_log("Unsupported ioctl: cmd=0x%04lx\n", cmd);
+ return -ENOSYS;
+ }
+ if (ie->target_cmd == cmd)
+ break;
+ ie++;
+ }
+ arg_type = ie->arg_type;
+#if defined(DEBUG)
+ gemu_log("ioctl: cmd=0x%04lx (%s)\n", cmd, ie->name);
+#endif
+ switch(arg_type[0]) {
+ case TYPE_NULL:
+ /* no argument */
+ ret = get_errno(ioctl(fd, ie->host_cmd));
+ break;
+ case TYPE_PTRVOID:
+ case TYPE_INT:
+ /* int argment */
+ ret = get_errno(ioctl(fd, ie->host_cmd, arg));
+ break;
+ case TYPE_PTR:
+ arg_type++;
+ target_size = thunk_type_size(arg_type, 0);
+ switch(ie->access) {
+ case IOC_R:
+ ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
+ if (!is_error(ret)) {
+ argptr = lock_user(arg, target_size, 0);
+ thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
+ unlock_user(argptr, arg, target_size);
+ }
+ break;
+ case IOC_W:
+ argptr = lock_user(arg, target_size, 1);
+ thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
+ unlock_user(argptr, arg, 0);
+ ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
+ break;
+ default:
+ case IOC_RW:
+ argptr = lock_user(arg, target_size, 1);
+ thunk_convert(buf_temp, argptr, arg_type, THUNK_HOST);
+ unlock_user(argptr, arg, 0);
+ ret = get_errno(ioctl(fd, ie->host_cmd, buf_temp));
+ if (!is_error(ret)) {
+ argptr = lock_user(arg, target_size, 0);
+ thunk_convert(argptr, buf_temp, arg_type, THUNK_TARGET);
+ unlock_user(argptr, arg, target_size);
+ }
+ break;
+ }
+ break;
+ default:
+ gemu_log("Unsupported ioctl type: cmd=0x%04lx type=%d\n", cmd, arg_type[0]);
+ ret = -ENOSYS;
+ break;
+ }
+ return ret;
+}
+
+/* ------------------------------------------------------------
+ Unix syscall handling
+*/
+
+static inline void byteswap_attrlist(struct attrlist *a)
+{
+ tswap16s(&a->bitmapcount);
+ tswap16s(&a->reserved);
+ tswap32s(&a->commonattr);
+ tswap32s(&a->volattr);
+ tswap32s(&a->dirattr);
+ tswap32s(&a->fileattr);
+ tswap32s(&a->forkattr);
+}
+
+struct attrbuf_header {
+ unsigned long length;
+};
+
+static inline void byteswap_attrbuf(struct attrbuf_header *attrbuf, struct attrlist *attrlist)
+{
+ DPRINTF("attrBuf.lenght %lx\n", attrbuf->length);
+}
+
+static inline void byteswap_statfs(struct statfs *s)
+{
+ tswap16s((uint16_t*)&s->f_otype);
+ tswap16s((uint16_t*)&s->f_oflags);
+ tswap32s((uint32_t*)&s->f_bsize);
+ tswap32s((uint32_t*)&s->f_iosize);
+ tswap32s((uint32_t*)&s->f_blocks);
+ tswap32s((uint32_t*)&s->f_bfree);
+ tswap32s((uint32_t*)&s->f_bavail);
+ tswap32s((uint32_t*)&s->f_files);
+ tswap32s((uint32_t*)&s->f_ffree);
+ tswap32s((uint32_t*)&s->f_fsid.val[0]);
+ tswap32s((uint32_t*)&s->f_fsid.val[1]);
+ tswap16s((uint16_t*)&s->f_reserved1);
+ tswap16s((uint16_t*)&s->f_type);
+ tswap32s((uint32_t*)&s->f_flags);
+}
+
+static inline void byteswap_stat(struct stat *s)
+{
+ tswap32s((uint32_t*)&s->st_dev);
+ tswap32s(&s->st_ino);
+ tswap16s(&s->st_mode);
+ tswap16s(&s->st_nlink);
+ tswap32s(&s->st_uid);
+ tswap32s(&s->st_gid);
+ tswap32s((uint32_t*)&s->st_rdev);
+ tswap32s((uint32_t*)&s->st_atimespec.tv_sec);
+ tswap32s((uint32_t*)&s->st_atimespec.tv_nsec);
+ tswap32s((uint32_t*)&s->st_mtimespec.tv_sec);
+ tswap32s((uint32_t*)&s->st_mtimespec.tv_nsec);
+ tswap32s((uint32_t*)&s->st_ctimespec.tv_sec);
+ tswap32s((uint32_t*)&s->st_ctimespec.tv_nsec);
+ tswap64s((uint64_t*)&s->st_size);
+ tswap64s((uint64_t*)&s->st_blocks);
+ tswap32s((uint32_t*)&s->st_blksize);
+ tswap32s(&s->st_flags);
+ tswap32s(&s->st_gen);
+}
+
+static inline void byteswap_dirents(struct dirent *d, int bytes)
+{
+ char *b;
+ for( b = (char*)d; (int)b < (int)d+bytes; )
+ {
+ unsigned short s = ((struct dirent *)b)->d_reclen;
+ tswap32s(&((struct dirent *)b)->d_ino);
+ tswap16s(&((struct dirent *)b)->d_reclen);
+ if(s<=0)
+ break;
+ b += s;
+ }
+}
+
+static inline void byteswap_iovec(struct iovec *v, int n)
+{
+ int i;
+ for(i = 0; i < n; i++)
+ {
+ tswap32s((uint32_t*)&v[i].iov_base);
+ tswap32s((uint32_t*)&v[i].iov_len);
+ }
+}
+
+static inline void byteswap_timeval(struct timeval *t)
+{
+ tswap32s((uint32_t*)&t->tv_sec);
+ tswap32s((uint32_t*)&t->tv_usec);
+}
+
+long do_unix_syscall_indirect(void *cpu_env, int num);
+long do_sync();
+long do_exit(uint32_t arg1);
+long do_getlogin(char *out, uint32_t size);
+long do_open(char * arg1, uint32_t arg2, uint32_t arg3);
+long do_getfsstat(struct statfs * arg1, uint32_t arg2, uint32_t arg3);
+long do_sigprocmask(uint32_t arg1, uint32_t * arg2, uint32_t * arg3);
+long do_execve(char* arg1, char ** arg2, char ** arg3);
+long do_getgroups(uint32_t arg1, gid_t * arg2);
+long do_gettimeofday(struct timeval * arg1, void * arg2);
+long do_readv(uint32_t arg1, struct iovec * arg2, uint32_t arg3);
+long do_writev(uint32_t arg1, struct iovec * arg2, uint32_t arg3);
+long do_utimes(char * arg1, struct timeval * arg2);
+long do_futimes(uint32_t arg1, struct timeval * arg2);
+long do_statfs(char * arg1, struct statfs * arg2);
+long do_fstatfs(uint32_t arg1, struct statfs * arg2);
+long do_stat(char * arg1, struct stat * arg2);
+long do_fstat(uint32_t arg1, struct stat * arg2);
+long do_lstat(char * arg1, struct stat * arg2);
+long do_getdirentries(uint32_t arg1, void* arg2, uint32_t arg3, void* arg4);
+long do_lseek(void *cpu_env, int num);
+long do___sysctl(int * name, uint32_t namelen, void * oldp, size_t * oldlenp, void * newp, size_t newlen /* ignored */);
+long do_getattrlist(void * arg1, void * arg2, void * arg3, uint32_t arg4, uint32_t arg5);
+long do_getdirentriesattr(uint32_t arg1, void * arg2, void * arg3, size_t arg4, void * arg5, void * arg6, void* arg7, uint32_t arg8);
+long do_fcntl(int fd, int cmd, int arg);
+
+long no_syscall(void *cpu_env, int num);
+
+long do_pread(uint32_t arg1, void * arg2, size_t arg3, off_t arg4)
+{
+ DPRINTF("0x%x, %p, 0x%lx, 0x%llx\n", arg1, arg2, arg3, arg4);
+ long ret = pread(arg1, arg2, arg3, arg4);
+ return ret;
+}
+
+long do_read(int d, void *buf, size_t nbytes)
+{
+ DPRINTF("0x%x, %p, 0x%lx\n", d, buf, nbytes);
+ long ret = get_errno(read(d, buf, nbytes));
+ if(!is_error(ret))
+ DPRINTF("%x\n", *(uint32_t*)buf);
+ return ret;
+}
+
+long unimpl_unix_syscall(void *cpu_env, int num);
+
+typedef long (*syscall_function_t)(void *cpu_env, int num);
+
+
+/* define a table that will handle the syscall number->function association */
+#define VOID void
+#define INT (uint32_t)get_int_arg(&i, cpu_env)
+#define INT64 (uint64_t)get_int64_arg(&i, cpu_env)
+#define UINT (unsigned int)INT
+#define PTR (void*)INT
+
+#define SIZE INT
+#define OFFSET INT64
+
+#define WRAPPER_CALL_DIRECT_0(function, args) long __qemu_##function(void *cpu_env) { return (long)function(); }
+#define WRAPPER_CALL_DIRECT_1(function, _arg1) long __qemu_##function(void *cpu_env) { int i = 0; typeof(_arg1) arg1 = _arg1; return (long)function(arg1); }
+#define WRAPPER_CALL_DIRECT_2(function, _arg1, _arg2) long __qemu_##function(void *cpu_env) { int i = 0; typeof(_arg1) arg1 = _arg1; typeof(_arg2) arg2 = _arg2; return (long)function(arg1, arg2); }
+#define WRAPPER_CALL_DIRECT_3(function, _arg1, _arg2, _arg3) long __qemu_##function(void *cpu_env) { int i = 0; typeof(_arg1) arg1 = _arg1; typeof(_arg2) arg2 = _arg2; typeof(_arg3) arg3 = _arg3; return (long)function(arg1, arg2, arg3); }
+#define WRAPPER_CALL_DIRECT_4(function, _arg1, _arg2, _arg3, _arg4) long __qemu_##function(void *cpu_env) { int i = 0; typeof(_arg1) arg1 = _arg1; typeof(_arg2) arg2 = _arg2; typeof(_arg3) arg3 = _arg3; typeof(_arg4) arg4 = _arg4; return (long)function(arg1, arg2, arg3, arg4); }
+#define WRAPPER_CALL_DIRECT_5(function, _arg1, _arg2, _arg3, _arg4, _arg5) long __qemu_##function(void *cpu_env) { int i = 0; typeof(_arg1) arg1 = _arg1; typeof(_arg2) arg2 = _arg2; typeof(_arg3) arg3 = _arg3; typeof(_arg4) arg4 = _arg4; typeof(_arg5) arg5 = _arg5; return (long)function(arg1, arg2, arg3, arg4, arg5); }
+#define WRAPPER_CALL_DIRECT_6(function, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6) long __qemu_##function(void *cpu_env) { int i = 0; typeof(_arg1) arg1 = _arg1; typeof(_arg2) arg2 = _arg2; typeof(_arg3) arg3 = _arg3; typeof(_arg4) arg4 = _arg4; typeof(_arg5) arg5 = _arg5; typeof(_arg6) arg6 = _arg6; return (long)function(arg1, arg2, arg3, arg4, arg5, arg6); }
+#define WRAPPER_CALL_DIRECT_7(function, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7) long __qemu_##function(void *cpu_env) { int i = 0; typeof(_arg1) arg1 = _arg1; typeof(_arg2) arg2 = _arg2; typeof(_arg3) arg3 = _arg3; typeof(_arg4) arg4 = _arg4; typeof(_arg5) arg5 = _arg5; typeof(_arg6) arg6 = _arg6; typeof(_arg7) arg7 = _arg7; return (long)function(arg1, arg2, arg3, arg4, arg5, arg6, arg7); }
+#define WRAPPER_CALL_DIRECT_8(function, _arg1, _arg2, _arg3, _arg4, _arg5, _arg6, _arg7, _arg8) long __qemu_##function(void *cpu_env) { int i = 0; typeof(_arg1) arg1 = _arg1; typeof(_arg2) arg2 = _arg2; typeof(_arg3) arg3 = _arg3; typeof(_arg4) arg4 = _arg4; typeof(_arg5) arg5 = _arg5; typeof(_arg6) arg6 = _arg6; typeof(_arg7) arg7 = _arg7; typeof(_arg8) arg8 = _arg8; return (long)function(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8); }
+#define WRAPPER_CALL_DIRECT(function, nargs, args...) WRAPPER_CALL_DIRECT_##nargs(function, args)
+#define WRAPPER_CALL_NOERRNO(function, nargs, args...) WRAPPER_CALL_DIRECT(function, nargs, args)
+#define WRAPPER_CALL_INDIRECT(function, nargs, args...)
+#define ENTRY(name, number, function, nargs, call_type, args...) WRAPPER_##call_type(function, nargs, args)
+
+#include "syscalls.h"
+
+#undef ENTRY
+#undef WRAPPER_CALL_DIRECT
+#undef WRAPPER_CALL_NOERRNO
+#undef WRAPPER_CALL_INDIRECT
+#undef OFFSET
+#undef SIZE
+#undef INT
+#undef PTR
+#undef INT64
+
+#define _ENTRY(name, number, function, nargs, call_type) [number] = {\
+ name, \
+ number, \
+ (syscall_function_t)function, \
+ nargs, \
+ call_type \
+ },
+
+#define ENTRY_CALL_DIRECT(name, number, function, nargs, call_type) _ENTRY(name, number, __qemu_##function, nargs, call_type)
+#define ENTRY_CALL_NOERRNO(name, number, function, nargs, call_type) ENTRY_CALL_DIRECT(name, number, function, nargs, call_type)
+#define ENTRY_CALL_INDIRECT(name, number, function, nargs, call_type) _ENTRY(name, number, function, nargs, call_type)
+#define ENTRY(name, number, function, nargs, call_type, args...) ENTRY_##call_type(name, number, function, nargs, call_type)
+
+#define CALL_DIRECT 1
+#define CALL_INDIRECT 2
+#define CALL_NOERRNO (CALL_DIRECT | 4 /* = 5 */)
+
+struct unix_syscall {
+ char * name;
+ int number;
+ syscall_function_t function;
+ int nargs;
+ int call_type;
+} unix_syscall_table[SYS_MAXSYSCALL] = {
+#include "syscalls.h"
+};
+
+#undef ENTRY
+#undef _ENTRY
+#undef ENTRY_CALL_DIRECT
+#undef ENTRY_CALL_INDIRECT
+#undef ENTRY_CALL_NOERRNO
+
+/* Actual syscalls implementation */
+
+long do_unix_syscall_indirect(void *cpu_env, int num)
+{
+ long ret;
+ int new_num;
+ int i = 0;
+
+ new_num = get_int_arg(&i, cpu_env);
+#ifdef TARGET_I386
+ ((CPUX86State*)cpu_env)->regs[R_ESP] += 4;
+ /* XXX: not necessary */
+ ((CPUX86State*)cpu_env)->regs[R_EAX] = new_num;
+#elif TARGET_PPC
+ {
+ int i;
+ uint32_t **regs = ((CPUPPCState*)cpu_env)->gpr;
+ for(i = 3; i < 11; i++)
+ *regs[i] = *regs[i+1];
+ /* XXX: not necessary */
+ *regs[0] = new_num;
+ }
+#endif
+ ret = do_unix_syscall(cpu_env, new_num);
+#ifdef TARGET_I386
+ ((CPUX86State*)cpu_env)->regs[R_ESP] -= 4;
+ /* XXX: not necessary */
+ ((CPUX86State*)cpu_env)->regs[R_EAX] = num;
+#elif TARGET_PPC
+ {
+ int i;
+ /* XXX: not really needed those regs are volatile accross calls */
+ uint32_t **regs = ((CPUPPCState*)cpu_env)->gpr;
+ for(i = 11; i > 3; i--)
+ *regs[i] = *regs[i-1];
+ regs[3] = new_num;
+ *regs[0] = num;
+ }
+#endif
+ return ret;
+}
+
+long do_exit(uint32_t arg1)
+{
+ exit(arg1);
+ /* not reached */
+ return -1;
+}
+
+long do_sync()
+{
+ sync();
+ return 0;
+}
+
+long do_getlogin(char *out, uint32_t size)
+{
+ char *login = getlogin();
+ if(!login)
+ return -1;
+ memcpy(out, login, size);
+ return 0;
+}
+long do_open(char * arg1, uint32_t arg2, uint32_t arg3)
+{
+ /* XXX: don't let the %s stay in there */
+ DPRINTF("open(%s, 0x%x, 0x%x)\n", arg1, arg2, arg3);
+ return get_errno(open(arg1, arg2, arg3));
+}
+
+long do_getfsstat(struct statfs * arg1, uint32_t arg2, uint32_t arg3)
+{
+ long ret;
+ DPRINTF("getfsstat(%p, 0x%x, 0x%x)\n", arg1, arg2, arg3);
+ ret = get_errno(getfsstat(arg1, arg2, arg3));
+ if((!is_error(ret)) && arg1)
+ byteswap_statfs(arg1);
+ return ret;
+}
+
+long do_sigprocmask(uint32_t arg1, uint32_t * arg2, uint32_t * arg3)
+{
+ long ret;
+ DPRINTF("sigprocmask(%d, %p, %p)\n", arg1, arg2, arg3);
+ gemu_log("XXX: sigprocmask not tested (%d, %p, %p)\n", arg1, arg2, arg3);
+ if(arg2)
+ tswap32s(arg2);
+ ret = get_errno(sigprocmask(arg1, (void *)arg2, (void *)arg3));
+ if((!is_error(ret)) && arg3)
+ tswap32s(arg3);
+ if(arg2)
+ tswap32s(arg2);
+ return ret;
+}
+
+long do_execve(char* arg1, char ** arg2, char ** arg3)
+{
+ long ret;
+ char **argv = arg2;
+ char **envp = arg3;
+ int argc;
+ int envc;
+
+ /* XXX: don't let the %s stay in here */
+ DPRINTF("execve(%s, %p, %p)\n", arg1, arg2, arg3);
+
+ for(argc = 0; argv[argc]; argc++);
+ for(envc = 0; envp[envc]; envc++);
+
+ argv = (char**)malloc(sizeof(char*)*argc);
+ envp = (char**)malloc(sizeof(char*)*envc);
+
+ for(; argc >= 0; argc--)
+ argv[argc] = (char*)tswap32((uint32_t)(arg2)[argc]);
+
+ for(; envc >= 0; envc--)
+ envp[envc] = (char*)tswap32((uint32_t)(arg3)[envc]);
+
+ ret = get_errno(execve(arg1, argv, envp));
+ free(argv);
+ free(envp);
+ return ret;
+}
+
+long do_getgroups(uint32_t arg1, gid_t * arg2)
+{
+ long ret;
+ int i;
+ DPRINTF("getgroups(0x%x, %p)\n", arg1, arg2);
+ ret = get_errno(getgroups(arg1, arg2));
+ if(ret > 0)
+ for(i = 0; i < arg1; i++)
+ tswap32s(&arg2[i]);
+ return ret;
+}
+
+long do_gettimeofday(struct timeval * arg1, void * arg2)
+{
+ long ret;
+ DPRINTF("gettimeofday(%p, %p)\n",
+ arg1, arg2);
+ ret = get_errno(gettimeofday(arg1, arg2));
+ if(!is_error(ret))
+ {
+ /* timezone no longer used according to the manpage, so don't bother with it */
+ byteswap_timeval(arg1);
+ }
+ return ret;
+}
+
+long do_readv(uint32_t arg1, struct iovec * arg2, uint32_t arg3)
+{
+ long ret;
+ DPRINTF("readv(0x%x, %p, 0x%x)\n", arg1, arg2, arg3);
+ if(arg2)
+ byteswap_iovec(arg2, arg3);
+ ret = get_errno(readv(arg1, arg2, arg3));
+ if((!is_error(ret)) && arg2)
+ byteswap_iovec(arg2, arg3);
+ return ret;
+}
+
+long do_writev(uint32_t arg1, struct iovec * arg2, uint32_t arg3)
+{
+ long ret;
+ DPRINTF("writev(0x%x, %p, 0x%x)\n", arg1, arg2, arg3);
+ if(arg2)
+ byteswap_iovec(arg2, arg3);
+ ret = get_errno(writev(arg1, arg2, arg3));
+ if((!is_error(ret)) && arg2)
+ byteswap_iovec(arg2, arg3);
+ return ret;
+}
+
+long do_utimes(char * arg1, struct timeval * arg2)
+{
+ DPRINTF("utimes(%p, %p)\n", arg1, arg2);
+ if(arg2)
+ {
+ byteswap_timeval(arg2);
+ byteswap_timeval(arg2+1);
+ }
+ return get_errno(utimes(arg1, arg2));
+}
+
+long do_futimes(uint32_t arg1, struct timeval * arg2)
+{
+ DPRINTF("futimes(0x%x, %p)\n", arg1, arg2);
+ if(arg2)
+ {
+ byteswap_timeval(arg2);
+ byteswap_timeval(arg2+1);
+ }
+ return get_errno(futimes(arg1, arg2));
+}
+
+long do_statfs(char * arg1, struct statfs * arg2)
+{
+ long ret;
+ DPRINTF("statfs(%p, %p)\n", arg1, arg2);
+ ret = get_errno(statfs(arg1, arg2));
+ if(!is_error(ret))
+ byteswap_statfs(arg2);
+ return ret;
+}
+
+long do_fstatfs(uint32_t arg1, struct statfs* arg2)
+{
+ long ret;
+ DPRINTF("fstatfs(0x%x, %p)\n",
+ arg1, arg2);
+ ret = get_errno(fstatfs(arg1, arg2));
+ if(!is_error(ret))
+ byteswap_statfs(arg2);
+
+ return ret;
+}
+
+long do_stat(char * arg1, struct stat * arg2)
+{
+ long ret;
+ /* XXX: don't let the %s stay in there */
+ DPRINTF("stat(%s, %p)\n", arg1, arg2);
+ ret = get_errno(stat(arg1, arg2));
+ if(!is_error(ret))
+ byteswap_stat(arg2);
+ return ret;
+}
+
+long do_fstat(uint32_t arg1, struct stat * arg2)
+{
+ long ret;
+ DPRINTF("fstat(0x%x, %p)\n", arg1, arg2);
+ ret = get_errno(fstat(arg1, arg2));
+ if(!is_error(ret))
+ byteswap_stat(arg2);
+ return ret;
+}
+
+long do_lstat(char * arg1, struct stat * arg2)
+{
+ long ret;
+ /* XXX: don't let the %s stay in there */
+ DPRINTF("lstat(%s, %p)\n", (const char *)arg1, arg2);
+ ret = get_errno(lstat(arg1, arg2));
+ if(!is_error(ret))
+ byteswap_stat(arg2);
+ return ret;
+}
+
+long do_getdirentries(uint32_t arg1, void* arg2, uint32_t arg3, void* arg4)
+{
+ long ret;
+ DPRINTF("getdirentries(0x%x, %p, 0x%x, %p)\n", arg1, arg2, arg3, arg4);
+ if(arg4)
+ tswap32s((uint32_t *)arg4);
+ ret = get_errno(getdirentries(arg1, arg2, arg3, arg4));
+ if(arg4)
+ tswap32s((uint32_t *)arg4);
+ if(!is_error(ret))
+ byteswap_dirents(arg2, ret);
+ return ret;
+}
+
+long do_lseek(void *cpu_env, int num)
+{
+ long ret;
+ int i = 0;
+ uint32_t arg1 = get_int_arg(&i, cpu_env);
+ uint64_t offset = get_int64_arg(&i, cpu_env);
+ uint32_t arg3 = get_int_arg(&i, cpu_env);
+ uint64_t r = lseek(arg1, offset, arg3);
+#ifdef TARGET_I386
+ /* lowest word in eax, highest in edx */
+ ret = r & 0xffffffff; /* will be set to eax after do_unix_syscall exit */
+ ((CPUX86State *)cpu_env)->regs[R_EDX] = (uint32_t)((r >> 32) & 0xffffffff) ;
+#elif defined TARGET_PPC
+ ret = r & 0xffffffff; /* will be set to r3 after do_unix_syscall exit */
+ ((CPUPPCState *)cpu_env)->gpr[4] = (uint32_t)((r >> 32) & 0xffffffff) ;
+#else
+ qerror("64 bit ret value on your arch?");
+#endif
+ return get_errno(ret);
+}
+
+void no_swap(void * oldp, int size)
+{
+}
+
+void sysctl_tswap32s(void * oldp, int size)
+{
+ tswap32s(oldp);
+}
+
+void bswap_oid(uint32_t * oldp, int size)
+{
+ int count = size / sizeof(int);
+ int i = 0;
+ do { tswap32s(oldp + i); } while (++i < count);
+}
+
+void sysctl_usrstack(uint32_t * oldp, int size)
+{
+ DPRINTF("sysctl_usrstack: 0x%x\n", *oldp);
+ tswap32s(oldp);
+}
+
+void sysctl_ncpu(uint32_t * ncpu, int size)
+{
+ *ncpu = 0x1;
+ DPRINTF("sysctl_ncpu: 0x%x\n", *ncpu);
+ tswap32s(ncpu);
+}
+
+void sysctl_exec(char * exec, int size)
+{
+ DPRINTF("sysctl_exec: %s\n", exec);
+}
+
+void sysctl_translate(char * exec, int size)
+{
+ DPRINTF("sysctl_translate: %s\n", exec);
+}
+
+struct sysctl_dir {
+ int num;
+ const char * name;
+ void (*swap_func)(void *, int);
+ struct sysctl_dir *childs;
+};
+
+#define ENTRYD(num, name, childs) { num, name, NULL, childs }
+#define ENTRYE(num, name, func) { num, name, (void (*)(void *, int))func, NULL }
+struct sysctl_dir sysctls_unspec[] = {
+ ENTRYE(3, "oip", bswap_oid),
+ { 0, NULL, NULL, NULL }
+};
+
+struct sysctl_dir sysctls_kern[] = {
+ ENTRYE(KERN_TRANSLATE, "translate", sysctl_translate), /* 44 */
+ ENTRYE(KERN_EXEC, "exec", sysctl_exec), /* 45 */
+ ENTRYE(KERN_USRSTACK32, "KERN_USRSTACK32", sysctl_usrstack), /* 35 */
+ ENTRYE(KERN_SHREG_PRIVATIZABLE, "KERN_SHREG_PRIVATIZABLE", sysctl_tswap32s), /* 54 */
+ { 0, NULL, NULL, NULL }
+};
+
+struct sysctl_dir sysctls_hw[] = {
+ ENTRYE(HW_NCPU, "ncpud", sysctl_tswap32s),
+ ENTRYE(104, "104", no_swap),
+ ENTRYE(105, "105", no_swap),
+ { 0, NULL, NULL, NULL }
+};
+
+struct sysctl_dir sysctls[] = {
+ ENTRYD(CTL_UNSPEC, "unspec", sysctls_unspec),
+ ENTRYD(CTL_KERN, "kern", sysctls_kern),
+ ENTRYD(CTL_HW, "hw", sysctls_hw ),
+ { 0, NULL, NULL, NULL }
+};
+
+#undef ENTRYE
+#undef ENTRYD
+
+static inline struct sysctl_dir * get_sysctl_entry_for_mib(int mib, struct sysctl_dir * sysctl_elmt)
+{
+ if(!sysctl_elmt)
+ return NULL;
+ for(; sysctl_elmt->name != NULL ; sysctl_elmt++) {
+ if(sysctl_elmt->num == mib)
+ return sysctl_elmt;
+ }
+ return NULL;
+}
+
+static inline long bswap_syctl(int * mib, int count, void *buf, int size)
+{
+ int i;
+ struct sysctl_dir * sysctl = sysctls;
+ struct sysctl_dir * ret = NULL;
+
+ for(i = 0; i < count; i++) {
+
+ if(!(ret = sysctl = get_sysctl_entry_for_mib(mib[i], sysctl))) {
+ gemu_log("bswap_syctl: can't find mib %d\n", mib[i]);
+ return -ENOTDIR;
+ }
+ if(!(sysctl = sysctl->childs))
+ break;
+ }
+
+ if(ret->childs)
+ qerror("we shouldn't have a directory element\n");
+
+ ret->swap_func(buf, size);
+ return 0;
+}
+
+static inline void print_syctl(int * mib, int count)
+{
+ int i;
+ struct sysctl_dir * sysctl = sysctls;
+ struct sysctl_dir * ret = NULL;
+
+ for(i = 0; i < count; i++) {
+ if(!(ret = sysctl = get_sysctl_entry_for_mib(mib[i], sysctl))){
+ gemu_log("print_syctl: can't find mib %d\n", mib[i]);
+ return;
+ }
+ DPRINTF("%s.", sysctl->name);
+ if(!(sysctl = sysctl->childs))
+ break;
+ }
+ DPRINTF("\n");
+}
+
+long do___sysctl(int * name, uint32_t namelen, void * oldp, size_t * oldlenp, void * newp, size_t newlen /* ignored */)
+{
+ long ret = 0;
+ int i;
+ DPRINTF("sysctl(%p, 0x%x, %p, %p, %p, 0x%lx)\n",
+ name, namelen, oldp, oldlenp, newp, newlen);
+ if(name) {
+ i = 0;
+ do { tswap32s( name + i); } while (++i < namelen);
+ print_syctl(name, namelen);
+ //bswap_syctl(name, namelen, newp, newlen);
+ tswap32s((uint32_t*)oldlenp);
+ }
+
+ if(name) /* Sometimes sysctl is called with no arg1, ignore */
+ ret = get_errno(sysctl(name, namelen, oldp, oldlenp, newp, newlen));
+
+#if defined(TARGET_I386) ^ defined(__i386__) || defined(TARGET_PPC) ^ defined(__ppc__)
+ if (!is_error(ret) && bswap_syctl(name, namelen, oldp, *oldlenp) != 0) {
+ return -ENOTDIR;
+ }
+#endif
+
+ if(name) {
+ //bswap_syctl(name, namelen, newp, newlen);
+ tswap32s((uint32_t*)oldlenp);
+
+ i = 0;
+ do { tswap32s( name + i); } while (++i < namelen);
+ }
+ return ret;
+}
+
+long do_getattrlist(void * arg1, void * arg2, void * arg3, uint32_t arg4, uint32_t arg5)
+{
+ struct attrlist * attrlist = (void *)arg2;
+ long ret;
+
+#if defined(TARGET_I386) ^ defined(__i386__) || defined(TARGET_PPC) ^ defined(__ppc__)
+ gemu_log("SYS_getdirentriesattr unimplemented\n");
+ return -ENOTSUP;
+#endif
+ /* XXX: don't let the %s stay in there */
+ DPRINTF("getattrlist(%s, %p, %p, 0x%x, 0x%x)\n",
+ (char *)arg1, arg2, arg3, arg4, arg5);
+
+ if(arg2) /* XXX: We should handle that in a copy especially
+ if the structure is not writable */
+ byteswap_attrlist(attrlist);
+
+ ret = get_errno(getattrlist((const char* )arg1, attrlist, (void *)arg3, arg4, arg5));
+
+ if(!is_error(ret))
+ {
+ byteswap_attrbuf((void *)arg3, attrlist);
+ byteswap_attrlist(attrlist);
+ }
+ return ret;
+}
+
+long do_getdirentriesattr(uint32_t arg1, void * arg2, void * arg3, size_t arg4, void * arg5, void * arg6, void* arg7, uint32_t arg8)
+{
+ DPRINTF("getdirentriesattr(0x%x, %p, %p, 0x%lx, %p, %p, %p, 0x%x)\n",
+ arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
+#if defined(TARGET_I386) ^ defined(__i386__) || defined(TARGET_PPC) ^ defined(__ppc__)
+ qerror("SYS_getdirentriesattr unimplemented\n");
+#endif
+
+ return get_errno(getdirentriesattr( arg1, (struct attrlist * )arg2, (void *)arg3, arg4,
+ (unsigned long *)arg5, (unsigned long *)arg6,
+ (unsigned long *)arg7, arg8));
+}
+
+static inline void bswap_flock(struct flock *f)
+{
+ tswap64s(&f->l_start);
+ tswap64s(&f->l_len);
+ tswap32s(&f->l_pid);
+ tswap16s(&f->l_type);
+ tswap16s(&f->l_whence);
+}
+
+static inline void bswap_fstore(struct fstore *f)
+{
+ tswap32s(&f->fst_flags);
+ tswap32s(&f->fst_posmode);
+ tswap64s(&f->fst_offset);
+ tswap64s(&f->fst_length);
+ tswap64s(&f->fst_bytesalloc);
+}
+
+static inline void bswap_radvisory(struct radvisory *f)
+{
+ tswap64s(&f->ra_offset);
+ tswap32s(&f->ra_count);
+}
+
+static inline void bswap_fbootstraptransfer(struct fbootstraptransfer *f)
+{
+ tswap64s(&f->fbt_offset);
+ tswap32s((uint32_t*)&f->fbt_length);
+ tswap32s((uint32_t*)&f->fbt_buffer); /* XXX: this is a ptr */
+}
+
+static inline void bswap_log2phys(struct log2phys *f)
+{
+ tswap32s(&f->l2p_flags);
+ tswap64s(&f->l2p_contigbytes);
+ tswap64s(&f->l2p_devoffset);
+}
+
+static inline void bswap_fcntl_arg(int cmd, void * arg)
+{
+ switch(cmd)
+ {
+ case F_DUPFD:
+ case F_GETFD:
+ case F_SETFD:
+ case F_GETFL:
+ case F_SETFL:
+ case F_GETOWN:
+ case F_SETOWN:
+ case F_SETSIZE:
+ case F_RDAHEAD:
+ case F_FULLFSYNC:
+ break;
+ case F_GETLK:
+ case F_SETLK:
+ case F_SETLKW:
+ bswap_flock(arg);
+ break;
+ case F_PREALLOCATE:
+ bswap_fstore(arg);
+ break;
+ case F_RDADVISE:
+ bswap_radvisory(arg);
+ break;
+ case F_READBOOTSTRAP:
+ case F_WRITEBOOTSTRAP:
+ bswap_fbootstraptransfer(arg);
+ break;
+ case F_LOG2PHYS:
+ bswap_log2phys(arg);
+ break;
+ default:
+ gemu_log("unknow cmd in fcntl\n");
+ }
+}
+
+long do_fcntl(int fd, int cmd, int arg)
+{
+ long ret;
+ bswap_fcntl_arg(cmd, (void *)arg);
+ ret = get_errno(fcntl(fd, cmd, arg));
+ if(!is_error(ret))
+ bswap_fcntl_arg(cmd, (void *)arg);
+ return ret;
+}
+
+long no_syscall(void *cpu_env, int num)
+{
+ /* XXX: We should probably fordward it to the host kernel */
+ qerror("no unix syscall %d\n", num);
+ /* not reached */
+ return -1;
+}
+
+long unimpl_unix_syscall(void *cpu_env, int num)
+{
+ if( (num < 0) || (num > SYS_MAXSYSCALL-1) )
+ qerror("unix syscall %d is out of unix syscall bounds (0-%d) " , num, SYS_MAXSYSCALL-1);
+
+ gemu_log("qemu: Unsupported unix syscall %s %d\n", unix_syscall_table[num].name , num);
+ gdb_handlesig (cpu_env, SIGTRAP);
+ exit(-1);
+}
+
+long do_unix_syscall(void *cpu_env, int num)
+{
+ long ret = 0;
+
+ DPRINTF("unix syscall %d: " , num);
+
+ if( (num < 0) || (num > SYS_MAXSYSCALL-1) )
+ qerror("unix syscall %d is out of unix syscall bounds (0-%d) " , num, SYS_MAXSYSCALL-1);
+
+ DPRINTF("%s [%s]", unix_syscall_table[num].name, unix_syscall_table[num].call_type & CALL_DIRECT ? "direct" : "indirect" );
+ ret = unix_syscall_table[num].function(cpu_env, num);
+
+ if(!(unix_syscall_table[num].call_type & CALL_NOERRNO))
+ ret = get_errno(ret);
+
+ DPRINTF("[returned 0x%x(%d)]\n", (int)ret, (int)ret);
+ return ret;
+}
+
+/* ------------------------------------------------------------
+ syscall_init
+*/
+void syscall_init(void)
+{
+ /* Nothing yet */
+}
Added: trunk/src/host/qemu-neo1973/darwin-user/syscalls.h
===================================================================
--- trunk/src/host/qemu-neo1973/darwin-user/syscalls.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/darwin-user/syscalls.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,384 @@
+/* generated from xnu/bsd/kern/syscalls.master */
+
+ ENTRY("syscall", SYS_syscall, do_unix_syscall_indirect, 0, CALL_INDIRECT, VOID) /* 0 indirect syscall */
+ ENTRY("exit", SYS_exit, do_exit, 1, CALL_DIRECT, INT) /* 1 */
+ ENTRY("fork", SYS_fork, fork, 0, CALL_NOERRNO, VOID) /* 2 */
+ ENTRY("read", SYS_read, do_read, 3, CALL_DIRECT, INT, PTR, SIZE) /* 3 */
+ ENTRY("write", SYS_write, write, 3, CALL_DIRECT, INT, PTR, SIZE) /* 4 */
+ ENTRY("open", SYS_open, do_open, 3, CALL_DIRECT, PTR, INT, INT) /* 5 */
+ ENTRY("close", SYS_close, close, 1, CALL_DIRECT, INT) /* 6 */
+ ENTRY("wait4", SYS_wait4, wait4, 4, CALL_DIRECT, INT, PTR, INT, PTR) /* 7 */
+ ENTRY("", 8, no_syscall, 0, CALL_INDIRECT, VOID) /* 8 old creat */
+ ENTRY("link", SYS_link, link, 2, CALL_DIRECT, PTR, PTR) /* 9 */
+ ENTRY("unlink", SYS_unlink, unlink, 1, CALL_DIRECT, PTR) /* 10 */
+ ENTRY("", 11, no_syscall, 0, CALL_INDIRECT, VOID) /* 11 old execv */
+ ENTRY("chdir", SYS_chdir, chdir, 1, CALL_DIRECT, PTR) /* 12 */
+ ENTRY("fchdir", SYS_fchdir, fchdir, 1, CALL_DIRECT, INT) /* 13 */
+ ENTRY("mknod", SYS_mknod, mknod, 3, CALL_DIRECT, PTR, INT, INT) /* 14 */
+ ENTRY("chmod", SYS_chmod, chmod, 2, CALL_DIRECT, PTR, INT) /* 15 */
+ ENTRY("chown", SYS_chown, chown, 3, CALL_DIRECT, PTR, INT, INT) /* 16 */
+ ENTRY("obreak", SYS_obreak, no_syscall, 1, CALL_INDIRECT, VOID) /* 17 old break */
+ ENTRY("ogetfsstat", 18, unimpl_unix_syscall, 3, CALL_INDIRECT, PTR, INT, INT) /* 18 */
+ ENTRY("", 19, no_syscall, 0, CALL_INDIRECT, VOID) /* 19 old lseek */
+ ENTRY("getpid", SYS_getpid, getpid, 0, CALL_NOERRNO, VOID) /* 20 */
+ ENTRY("", 21, no_syscall, 0, CALL_INDIRECT, VOID) /* 21 old mount */
+ ENTRY("", 22, no_syscall, 0, CALL_INDIRECT, VOID) /* 22 old umount */
+ ENTRY("setuid", SYS_setuid, setuid, 1, CALL_DIRECT, INT) /* 23 */
+ ENTRY("getuid", SYS_getuid, getuid, 0, CALL_NOERRNO, VOID) /* 24 */
+ ENTRY("geteuid", SYS_geteuid, geteuid, 0, CALL_NOERRNO, VOID) /* 25 */
+ ENTRY("ptrace", SYS_ptrace, ptrace, 4, CALL_DIRECT, INT, INT, PTR, INT) /* 26 */
+ ENTRY("recvmsg", SYS_recvmsg, recvmsg, 3, CALL_DIRECT, INT, PTR, INT) /* 27 */
+ ENTRY("sendmsg", SYS_sendmsg, sendmsg, 3, CALL_DIRECT, INT, PTR, INT) /* 28 */
+ ENTRY("recvfrom", SYS_recvfrom, recvfrom, 6, CALL_DIRECT, INT, PTR, INT, INT, PTR, PTR) /* 29 */
+ ENTRY("accept", SYS_accept, accept, 3, CALL_DIRECT, INT, PTR, PTR) /* 30 */
+ ENTRY("getpeername", SYS_getpeername, getpeername, 3, CALL_DIRECT, INT, PTR, PTR) /* 31 */
+ ENTRY("getsockname", SYS_getsockname, getsockname, 3, CALL_DIRECT, INT, PTR, PTR) /* 32 */
+ ENTRY("access", SYS_access, access, 2, CALL_DIRECT, PTR, INT) /* 33 */
+ ENTRY("chflags", SYS_chflags, chflags, 2, CALL_DIRECT, PTR, INT) /* 34 */
+ ENTRY("fchflags", SYS_fchflags, fchflags, 2, CALL_DIRECT, INT, INT) /* 35 */
+ ENTRY("sync", SYS_sync, do_sync, 0, CALL_INDIRECT, VOID) /* 36 */
+ ENTRY("kill", SYS_kill, kill, 2, CALL_DIRECT, INT, INT) /* 37 */
+ ENTRY("", 38, no_syscall, 0, CALL_INDIRECT, VOID) /* 38 old stat */
+ ENTRY("getppid", SYS_getppid, getppid, 0, CALL_DIRECT, VOID) /* 39 */
+ ENTRY("", 40, no_syscall, 0, CALL_INDIRECT, VOID) /* 40 old lstat */
+ ENTRY("dup", SYS_dup, dup, 1, CALL_DIRECT, INT) /* 41 */
+ ENTRY("pipe", SYS_pipe, pipe, 0, CALL_INDIRECT, PTR) /* 42 */
+ ENTRY("getegid", SYS_getegid, getegid, 0, CALL_NOERRNO, VOID) /* 43 */
+ ENTRY("profil", SYS_profil, profil, 4, CALL_DIRECT, PTR, SIZE, INT, INT) /* 44 */
+ ENTRY("ktrace", SYS_ktrace, no_syscall, 4, CALL_INDIRECT, VOID) /* 45 */
+ ENTRY("sigaction", SYS_sigaction, do_sigaction, 3, CALL_DIRECT, INT, PTR, PTR) /* 46 */
+ ENTRY("getgid", SYS_getgid, getgid, 0, CALL_NOERRNO, VOID) /* 47 */
+ ENTRY("sigprocmask", SYS_sigprocmask, do_sigprocmask, 3, CALL_DIRECT, INT, PTR, PTR) /* 48 */
+ ENTRY("getlogin", SYS_getlogin, do_getlogin, 2, CALL_DIRECT, PTR, UINT) /* 49 XXX */
+ ENTRY("setlogin", SYS_setlogin, setlogin, 1, CALL_DIRECT, PTR) /* 50 */
+ ENTRY("acct", SYS_acct, acct, 1, CALL_DIRECT, PTR) /* 51 */
+ ENTRY("sigpending", SYS_sigpending, sigpending, 1, CALL_DIRECT, PTR) /* 52 */
+ ENTRY("sigaltstack", SYS_sigaltstack, do_sigaltstack, 2, CALL_DIRECT, PTR, PTR) /* 53 */
+ ENTRY("ioctl", SYS_ioctl, do_ioctl, 3, CALL_DIRECT, INT, INT, INT) /* 54 */
+ ENTRY("reboot", SYS_reboot, unimpl_unix_syscall, 2, CALL_INDIRECT, INT, PTR) /* 55 */
+ ENTRY("revoke", SYS_revoke, revoke, 1, CALL_DIRECT, PTR) /* 56 */
+ ENTRY("symlink", SYS_symlink, symlink, 2, CALL_DIRECT, PTR, PTR) /* 57 */
+ ENTRY("readlink", SYS_readlink, readlink, 3, CALL_DIRECT, PTR, PTR, INT) /* 58 */
+ ENTRY("execve", SYS_execve, do_execve, 3, CALL_DIRECT, PTR, PTR, PTR) /* 59 */
+ ENTRY("umask", SYS_umask, umask, 1, CALL_DIRECT, INT) /* 60 */
+ ENTRY("chroot", SYS_chroot, chroot, 1, CALL_DIRECT, PTR) /* 61 */
+ ENTRY("", 62, no_syscall, 0, CALL_INDIRECT, VOID) /* 62 old fstat */
+ ENTRY("", 63, no_syscall, 0, CALL_INDIRECT, VOID) /* 63 used internally , reserved */
+ ENTRY("", 64, no_syscall, 0, CALL_INDIRECT, VOID) /* 64 old getpagesize */
+ ENTRY("msync", SYS_msync, target_msync, 3, CALL_DIRECT, UINT /*PTR*/, SIZE, INT) /* 65 */
+ ENTRY("vfork", SYS_vfork, vfork, 0, CALL_DIRECT, VOID) /* 66 */
+ ENTRY("", 67, no_syscall, 0, CALL_INDIRECT, VOID) /* 67 old vread */
+ ENTRY("", 68, no_syscall, 0, CALL_INDIRECT, VOID) /* 68 old vwrite */
+ ENTRY("sbrk", SYS_sbrk, sbrk, 1, CALL_DIRECT, INT) /* 69 */
+ ENTRY("sstk", SYS_sstk, no_syscall, 1, CALL_INDIRECT, VOID) /* 70 */
+ ENTRY("", 71, no_syscall, 0, CALL_INDIRECT, VOID) /* 71 old mmap */
+ ENTRY("ovadvise", SYS_ovadvise, no_syscall, 0, CALL_INDIRECT, VOID) /* 72 old vadvise */
+ ENTRY("munmap", SYS_munmap, target_munmap, 2, CALL_DIRECT, UINT /* PTR */, SIZE) /* 73 */
+ ENTRY("mprotect", SYS_mprotect, mprotect, 3, CALL_DIRECT, PTR, SIZE, INT) /* 74 */
+ ENTRY("madvise", SYS_madvise, madvise, 3, CALL_DIRECT, PTR, SIZE, INT) /* 75 */
+ ENTRY("", 76, no_syscall, 0, CALL_INDIRECT, VOID) /* 76 old vhangup */
+ ENTRY("", 77, no_syscall, 0, CALL_INDIRECT, VOID) /* 77 old vlimit */
+ ENTRY("mincore", SYS_mincore, mincore, 3, CALL_DIRECT, PTR, SIZE, PTR) /* 78 */
+ ENTRY("getgroups", SYS_getgroups, do_getgroups, 2, CALL_DIRECT, UINT, PTR) /* 79 */
+ ENTRY("setgroups", SYS_setgroups, setgroups, 2, CALL_DIRECT, UINT, PTR) /* 80 */
+ ENTRY("getpgrp", SYS_getpgrp, getpgrp, 0, CALL_DIRECT, VOID) /* 81 */
+ ENTRY("setpgid", SYS_setpgid, setpgid, 2, CALL_DIRECT, INT, INT) /* 82 */
+ ENTRY("setitimer", SYS_setitimer, setitimer, 3, CALL_DIRECT, INT, PTR, PTR) /* 83 */
+ ENTRY("", 84, no_syscall, 0, CALL_INDIRECT, VOID) /* 84 old wait */
+ ENTRY("swapon", SYS_swapon, unimpl_unix_syscall, 0, CALL_INDIRECT, VOID) /* 85 */
+ ENTRY("getitimer", SYS_getitimer, getitimer, 2, CALL_DIRECT, INT, PTR) /* 86 */
+ ENTRY("", 87, no_syscall, 0, CALL_INDIRECT, VOID) /* 87 old gethostname */
+ ENTRY("", 88, no_syscall, 0, CALL_INDIRECT, VOID) /* 88 old sethostname */
+ ENTRY("getdtablesize", SYS_getdtablesize, getdtablesize, 0, CALL_DIRECT, VOID) /* 89 */
+ ENTRY("dup2", SYS_dup2, dup2, 2, CALL_DIRECT, INT, INT) /* 90 */
+ ENTRY("", 91, no_syscall, 0, CALL_INDIRECT, VOID) /* 91 old getdopt */
+ ENTRY("fcntl", SYS_fcntl, do_fcntl, 3, CALL_DIRECT, INT, INT, INT) /* 92 */
+ ENTRY("select", SYS_select, select, 5, CALL_DIRECT, INT, PTR, PTR, PTR, PTR) /* 93 */
+ ENTRY("", 94, no_syscall, 0, CALL_INDIRECT, VOID) /* 94 old setdopt */
+ ENTRY("fsync", SYS_fsync, fsync, 1, CALL_DIRECT, INT) /* 95 */
+ ENTRY("setpriority", SYS_setpriority, setpriority, 3, CALL_DIRECT, INT, INT, INT) /* 96 */
+ ENTRY("socket", SYS_socket, socket, 3, CALL_DIRECT, INT, INT, INT) /* 97 */
+ ENTRY("connect", SYS_connect, connect, 3, CALL_DIRECT, INT, PTR, INT) /* 98 */
+ ENTRY("", 99, no_syscall, 0, CALL_INDIRECT, VOID) /* 99 old accept */
+ ENTRY("getpriority", SYS_getpriority, getpriority, 2, CALL_DIRECT, INT, INT) /* 100 */
+ ENTRY("", 101, no_syscall, 0, CALL_INDIRECT, VOID) /* 101 old send */
+ ENTRY("", 102, no_syscall, 0, CALL_INDIRECT, VOID) /* 102 old recv */
+ ENTRY("", 103, no_syscall, 0, CALL_INDIRECT, VOID) /* 103 old sigreturn */
+ ENTRY("bind", SYS_bind, bind, 3, CALL_DIRECT, INT, PTR, INT) /* 104 */
+ ENTRY("setsockopt", SYS_setsockopt, setsockopt, 5, CALL_DIRECT, INT, INT, INT, PTR, INT) /* 105 */
+ ENTRY("listen", SYS_listen, listen, 2, CALL_DIRECT, INT, INT) /* 106 */
+ ENTRY("", 107, no_syscall, 0, CALL_INDIRECT, VOID) /* 107 old vtimes */
+ ENTRY("", 108, no_syscall, 0, CALL_INDIRECT, VOID) /* 108 old sigvec */
+ ENTRY("", 109, no_syscall, 0, CALL_INDIRECT, VOID) /* 109 old sigblock */
+ ENTRY("", 110, no_syscall, 0, CALL_INDIRECT, VOID) /* 110 old sigsetmask */
+ ENTRY("sigsuspend", SYS_sigsuspend, unimpl_unix_syscall, 1, CALL_INDIRECT, INT) /* 111 */
+ ENTRY("", 112, no_syscall, 0, CALL_INDIRECT, VOID) /* 112 old sigstack */
+ ENTRY("", 113, no_syscall, 0, CALL_INDIRECT, VOID) /* 113 old recvmsg */
+ ENTRY("", 114, no_syscall, 0, CALL_INDIRECT, VOID) /* 114 old sendmsg */
+ ENTRY("", 115, no_syscall, 0, CALL_INDIRECT, VOID) /* 115 old vtrace */
+ ENTRY("gettimeofday", SYS_gettimeofday, do_gettimeofday, 2, CALL_DIRECT, PTR, PTR) /* 116 */
+ ENTRY("getrusage", SYS_getrusage, getrusage, 2, CALL_DIRECT, INT, PTR) /* 117 */
+ ENTRY("getsockopt", SYS_getsockopt, getsockopt, 5, CALL_DIRECT, INT, INT, INT, PTR, PTR) /* 118 */
+ ENTRY("", 119, no_syscall, 0, CALL_INDIRECT, VOID) /* 119 old resuba */
+ ENTRY("readv", SYS_readv, do_readv, 3, CALL_DIRECT, INT, PTR, UINT) /* 120 */
+ ENTRY("writev", SYS_writev, do_writev, 3, CALL_DIRECT, INT, PTR, UINT) /* 121 */
+ ENTRY("settimeofday", SYS_settimeofday, settimeofday, 2, CALL_DIRECT, PTR, PTR) /* 122 */
+ ENTRY("fchown", SYS_fchown, fchown, 3, CALL_DIRECT, INT, INT, INT) /* 123 */
+ ENTRY("fchmod", SYS_fchmod, fchmod, 2, CALL_DIRECT, INT, INT) /* 124 */
+ ENTRY("", 125, no_syscall, 0, CALL_INDIRECT, VOID) /* 125 old recvfrom */
+ ENTRY("", 126, no_syscall, 0, CALL_INDIRECT, VOID) /* 126 old setreuid */
+ ENTRY("", 127, no_syscall, 0, CALL_INDIRECT, VOID) /* 127 old setregid */
+ ENTRY("rename", SYS_rename, rename, 2, CALL_DIRECT, PTR, PTR) /* 128 */
+ ENTRY("", 129, no_syscall, 0, CALL_INDIRECT, VOID) /* 129 old truncate */
+ ENTRY("", 130, no_syscall, 0, CALL_INDIRECT, VOID) /* 130 old ftruncate */
+ ENTRY("flock", SYS_flock, flock, 2, CALL_DIRECT, INT, INT) /* 131 */
+ ENTRY("mkfifo", SYS_mkfifo, mkfifo, 2, CALL_DIRECT, PTR, INT) /* 132 */
+ ENTRY("sendto", SYS_sendto, sendto, 6, CALL_DIRECT, INT, PTR, SIZE, INT, PTR, INT) /* 133 */
+ ENTRY("shutdown", SYS_shutdown, shutdown, 2, CALL_DIRECT, INT, INT) /* 134 */
+ ENTRY("socketpair", SYS_socketpair, socketpair, 4, CALL_DIRECT, INT, INT, INT, PTR) /* 135 */
+ ENTRY("mkdir", SYS_mkdir, mkdir, 2, CALL_DIRECT, PTR, INT) /* 136 */
+ ENTRY("rmdir", SYS_rmdir, rmdir, 1, CALL_DIRECT, PTR) /* 137 */
+ ENTRY("utimes", SYS_utimes, do_utimes, 2, CALL_DIRECT, PTR, PTR) /* 138 */
+ ENTRY("futimes", SYS_futimes, do_futimes, 2, CALL_DIRECT, INT, PTR) /* 139 */
+ ENTRY("adjtime", SYS_adjtime, adjtime, 2, CALL_DIRECT, PTR, PTR) /* 140 */
+ ENTRY("", 141, no_syscall, 0, CALL_INDIRECT, VOID) /* 141 old getpeername */
+ ENTRY("", 142, no_syscall, 0, CALL_INDIRECT, VOID) /* 142 old gethostid */
+ ENTRY("", 143, no_syscall, 0, CALL_INDIRECT, VOID) /* 143 old sethostid */
+ ENTRY("", 144, no_syscall, 0, CALL_INDIRECT, VOID) /* 144 old getrlimit */
+ ENTRY("", 145, no_syscall, 0, CALL_INDIRECT, VOID) /* 145 old setrlimit */
+ ENTRY("", 146, no_syscall, 0, CALL_INDIRECT, VOID) /* 146 old killpg */
+ ENTRY("setsid", SYS_setsid, setsid, 0, CALL_DIRECT, VOID) /* 147 */
+ ENTRY("", 148, no_syscall, 0, CALL_INDIRECT, VOID) /* 148 old setquota */
+ ENTRY("", 149, no_syscall, 0, CALL_INDIRECT, VOID) /* 149 old qquota */
+ ENTRY("", 150, no_syscall, 0, CALL_INDIRECT, VOID) /* 150 old getsockname */
+ ENTRY("getpgid", SYS_getpgid, getpgid, 1, CALL_DIRECT, INT) /* 151 */
+ ENTRY("setprivexec", SYS_setprivexec, no_syscall, 1, CALL_INDIRECT, VOID) /* 152 */
+ ENTRY("pread", SYS_pread, do_pread, 4, CALL_DIRECT, INT, PTR, SIZE, OFFSET) /* 153 */
+ ENTRY("pwrite", SYS_pwrite, pwrite, 4, CALL_DIRECT, INT, PTR, SIZE, OFFSET) /* 154 */
+#ifdef SYS_nfssvc
+ ENTRY("nfssvc", SYS_nfssvc, nfssvc, 2, CALL_DIRECT, INT, PTR) /* 155 */
+#else
+ ENTRY("nfssvc", 155, no_syscall, 2, CALL_INDIRECT, VOID) /* 155 */
+#endif
+ ENTRY("", 155, no_syscall, 0, CALL_INDIRECT, VOID) /* 155 */
+ ENTRY("", 156, no_syscall, 0, CALL_INDIRECT, VOID) /* 156 old getdirentries */
+ ENTRY("statfs", SYS_statfs, do_statfs, 2, CALL_DIRECT, PTR, PTR) /* 157 */
+ ENTRY("fstatfs", SYS_fstatfs, do_fstatfs, 2, CALL_DIRECT, INT, PTR) /* 158 */
+ ENTRY("unmount", SYS_unmount, unmount, 2, CALL_DIRECT, PTR, INT) /* 159 */
+ ENTRY("", 160, no_syscall, 0, CALL_INDIRECT, VOID) /* 160 old async_daemon */
+ ENTRY("", 161, no_syscall, 0, CALL_INDIRECT, VOID) /* 161 */
+ ENTRY("", 162, no_syscall, 0, CALL_INDIRECT, VOID) /* 162 old getdomainname */
+ ENTRY("", 163, no_syscall, 0, CALL_INDIRECT, VOID) /* 163 old setdomainname */
+ ENTRY("", 164, no_syscall, 0, CALL_INDIRECT, VOID) /* 164 */
+ ENTRY("quotactl", SYS_quotactl, no_syscall, 4, CALL_INDIRECT, VOID) /* 165 */
+ ENTRY("", 166, no_syscall, 0, CALL_INDIRECT, VOID) /* 166 old exportfs */
+ ENTRY("mount", SYS_mount, mount, 4, CALL_DIRECT, PTR, PTR, INT, PTR) /* 167 */
+ ENTRY("", 168, no_syscall, 0, CALL_INDIRECT, VOID) /* 168 old ustat */
+ ENTRY("", 169, no_syscall, 0, CALL_INDIRECT, VOID) /* 169 */
+ ENTRY("table", SYS_table, no_syscall, 0, CALL_INDIRECT, VOID) /* 170 old table */
+ ENTRY("", 171, no_syscall, 0, CALL_INDIRECT, VOID) /* 171 old wait3 */
+ ENTRY("", 172, no_syscall, 0, CALL_INDIRECT, VOID) /* 172 old rpause */
+ ENTRY("waitid", SYS_waitid, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 173 */
+ ENTRY("", 174, no_syscall, 0, CALL_INDIRECT, VOID) /* 174 old getdents */
+ ENTRY("", 175, no_syscall, 0, CALL_INDIRECT, VOID) /* 175 old gc_control */
+ ENTRY("add_profil", SYS_add_profil, add_profil, 4, CALL_DIRECT, PTR, SIZE, UINT, UINT) /* 176 */
+ ENTRY("", 177, no_syscall, 0, CALL_INDIRECT, VOID) /* 177 */
+ ENTRY("", 178, no_syscall, 0, CALL_INDIRECT, VOID) /* 178 */
+ ENTRY("", 179, no_syscall, 0, CALL_INDIRECT, VOID) /* 179 */
+ ENTRY("kdebug_trace", SYS_kdebug_trace, no_syscall, 6, CALL_INDIRECT, VOID) /* 180 */
+ ENTRY("setgid", SYS_setgid, setgid, 1, CALL_DIRECT, INT) /* 181 */
+ ENTRY("setegid", SYS_setegid, setegid, 1, CALL_DIRECT, INT) /* 182 */
+ ENTRY("seteuid", SYS_seteuid, seteuid, 1, CALL_DIRECT, INT) /* 183 */
+ ENTRY("sigreturn", SYS_sigreturn, do_sigreturn, 2, CALL_INDIRECT, PTR, INT) /* 184 */
+ ENTRY("chud", SYS_chud, unimpl_unix_syscall, 6, CALL_INDIRECT, VOID) /* 185 */
+ ENTRY("", 186, no_syscall, 0, CALL_INDIRECT, VOID) /* 186 */
+ ENTRY("", 187, no_syscall, 0, CALL_INDIRECT, VOID) /* 187 */
+ ENTRY("stat", SYS_stat, do_stat, 2, CALL_DIRECT, PTR, PTR) /* 188 */
+ ENTRY("fstat", SYS_fstat, do_fstat, 2, CALL_DIRECT, INT, PTR) /* 189 */
+ ENTRY("lstat", SYS_lstat, do_lstat, 2, CALL_DIRECT, PTR, PTR) /* 190 */
+ ENTRY("pathconf", SYS_pathconf, pathconf, 2, CALL_DIRECT, PTR, INT) /* 191 */
+ ENTRY("fpathconf", SYS_fpathconf, fpathconf, 2, CALL_DIRECT, INT, INT) /* 192 */
+ ENTRY("getfsstat", SYS_getfsstat, do_getfsstat, 3, CALL_DIRECT, PTR, INT, INT) /* 193 */
+ ENTRY("", 193, no_syscall, 0, CALL_INDIRECT, VOID) /* 193 */
+ ENTRY("getrlimit", SYS_getrlimit, getrlimit, 2, CALL_DIRECT, UINT, PTR) /* 194 */
+ ENTRY("setrlimit", SYS_setrlimit, setrlimit, 2, CALL_DIRECT, UINT, PTR) /* 195 */
+ ENTRY("getdirentries", SYS_getdirentries, do_getdirentries, 4, CALL_DIRECT, INT, PTR, UINT, PTR) /* 196 */
+ ENTRY("mmap", SYS_mmap, target_mmap, 6, CALL_DIRECT, UINT /*PTR*/, SIZE, INT, INT, INT, OFFSET) /* 197 */
+ ENTRY("", 198, no_syscall, 0, CALL_INDIRECT, VOID) /* 198 __syscall */
+ ENTRY("lseek", SYS_lseek, do_lseek, 3, CALL_INDIRECT, INT, OFFSET, INT) /* 199 */
+ ENTRY("truncate", SYS_truncate, truncate, 2, CALL_DIRECT, PTR, OFFSET) /* 200 */
+ ENTRY("ftruncate", SYS_ftruncate, ftruncate, 2, CALL_DIRECT, INT, OFFSET) /* 201 */
+ ENTRY("__sysctl", SYS___sysctl, do___sysctl, 6, CALL_DIRECT, PTR, INT, PTR, PTR, PTR, SIZE) /* 202 */
+ ENTRY("mlock", SYS_mlock, mlock, 2, CALL_DIRECT, PTR, SIZE) /* 203 */
+ ENTRY("munlock", SYS_munlock, munlock, 2, CALL_DIRECT, PTR, SIZE) /* 204 */
+ ENTRY("undelete", SYS_undelete, undelete, 1, CALL_DIRECT, PTR) /* 205 */
+ ENTRY("ATsocket", SYS_ATsocket, no_syscall, 1, CALL_INDIRECT, VOID) /* 206 */
+ ENTRY("ATgetmsg", SYS_ATgetmsg, no_syscall, 4, CALL_INDIRECT, VOID) /* 207 */
+ ENTRY("ATputmsg", SYS_ATputmsg, no_syscall, 4, CALL_INDIRECT, VOID) /* 208 */
+ ENTRY("ATPsndreq", SYS_ATPsndreq, no_syscall, 4, CALL_INDIRECT, VOID) /* 209 */
+ ENTRY("ATPsndrsp", SYS_ATPsndrsp, no_syscall, 4, CALL_INDIRECT, VOID) /* 210 */
+ ENTRY("ATPgetreq", SYS_ATPgetreq, no_syscall, 3, CALL_INDIRECT, VOID) /* 211 */
+ ENTRY("ATPgetrsp", SYS_ATPgetrsp, no_syscall, 2, CALL_INDIRECT, VOID) /* 212 */
+ ENTRY("", 213, no_syscall, 0, CALL_INDIRECT, VOID) /* 213 Reserved for AppleTalk */
+ ENTRY("kqueue_from_portset_np", SYS_kqueue_from_portset_np, no_syscall, 1, CALL_INDIRECT, VOID) /* 214 */
+ ENTRY("kqueue_portset_np", SYS_kqueue_portset_np, no_syscall, 1, CALL_INDIRECT, VOID) /* 215 */
+ ENTRY("mkcomplex", SYS_mkcomplex, no_syscall, 3, CALL_INDIRECT, VOID) /* 216 soon to be obsolete */
+ ENTRY("statv", SYS_statv, no_syscall, 2, CALL_INDIRECT, VOID) /* 217 soon to be obsolete */
+ ENTRY("lstatv", SYS_lstatv, no_syscall, 2, CALL_INDIRECT, VOID) /* 218 soon to be obsolete */
+ ENTRY("fstatv", SYS_fstatv, no_syscall, 2, CALL_INDIRECT, VOID) /* 219 soon to be obsolete */
+ ENTRY("getattrlist", SYS_getattrlist, do_getattrlist, 5, CALL_DIRECT, PTR, PTR, PTR, SIZE, UINT) /* 220 */
+ ENTRY("setattrlist", SYS_setattrlist, unimpl_unix_syscall, 5, CALL_INDIRECT, VOID) /* 221 */
+ ENTRY("getdirentriesattr", SYS_getdirentriesattr, do_getdirentriesattr, 8, CALL_DIRECT, INT, PTR, PTR, SIZE, PTR, PTR, PTR, UINT) /* 222 */
+ ENTRY("exchangedata", SYS_exchangedata, exchangedata, 3, CALL_DIRECT, PTR, PTR, UINT) /* 223 */
+ ENTRY("checkuseraccess", SYS_checkuseraccess, checkuseraccess, 6, CALL_DIRECT, PTR, INT, PTR, INT, INT, UINT) /* 224 */
+ ENTRY("", 224, no_syscall, 0, CALL_INDIRECT, VOID) /* 224 HFS checkuseraccess check access to a file */
+ ENTRY("searchfs", SYS_searchfs, searchfs, 6, CALL_DIRECT, PTR, PTR, PTR, UINT, UINT, PTR) /* 225 */
+ ENTRY("delete", SYS_delete, no_syscall, 1, CALL_INDIRECT, VOID) /* 226 private delete ( Carbon semantics ) */
+ ENTRY("copyfile", SYS_copyfile, no_syscall, 4, CALL_INDIRECT, VOID) /* 227 */
+ ENTRY("", 228, no_syscall, 0, CALL_INDIRECT, VOID) /* 228 */
+ ENTRY("", 229, no_syscall, 0, CALL_INDIRECT, VOID) /* 229 */
+ ENTRY("poll", SYS_poll, no_syscall, 3, CALL_INDIRECT, VOID) /* 230 */
+ ENTRY("watchevent", SYS_watchevent, no_syscall, 2, CALL_INDIRECT, VOID) /* 231 */
+ ENTRY("waitevent", SYS_waitevent, no_syscall, 2, CALL_INDIRECT, VOID) /* 232 */
+ ENTRY("modwatch", SYS_modwatch, no_syscall, 2, CALL_INDIRECT, VOID) /* 233 */
+ ENTRY("getxattr", SYS_getxattr, no_syscall, 6, CALL_INDIRECT, VOID) /* 234 */
+ ENTRY("fgetxattr", SYS_fgetxattr, no_syscall, 6, CALL_INDIRECT, VOID) /* 235 */
+ ENTRY("setxattr", SYS_setxattr, no_syscall, 6, CALL_INDIRECT, VOID) /* 236 */
+ ENTRY("fsetxattr", SYS_fsetxattr, no_syscall, 6, CALL_INDIRECT, VOID) /* 237 */
+ ENTRY("removexattr", SYS_removexattr, no_syscall, 3, CALL_INDIRECT, VOID) /* 238 */
+ ENTRY("fremovexattr", SYS_fremovexattr, no_syscall, 3, CALL_INDIRECT, VOID) /* 239 */
+ ENTRY("listxattr", SYS_listxattr, listxattr, 4, CALL_INDIRECT, VOID) /* 240 */
+ ENTRY("flistxattr", SYS_flistxattr, no_syscall, 4, CALL_INDIRECT, VOID) /* 241 */
+ ENTRY("fsctl", SYS_fsctl, fsctl, 4, CALL_DIRECT, PTR, UINT, PTR, UINT) /* 242 */
+ ENTRY("initgroups", SYS_initgroups, unimpl_unix_syscall, 3, CALL_INDIRECT, UINT, PTR, INT) /* 243 */
+ ENTRY("", 244, no_syscall, 0, CALL_INDIRECT, VOID) /* 244 */
+ ENTRY("", 245, no_syscall, 0, CALL_INDIRECT, VOID) /* 245 */
+ ENTRY("", 246, no_syscall, 0, CALL_INDIRECT, VOID) /* 246 */
+#ifdef SYS_nfsclnt
+ ENTRY("nfsclnt", SYS_nfsclnt, nfsclnt, 2, CALL_DIRECT, INT, PTR) /* 247 */
+#else
+ ENTRY("nfsclnt", 247, no_syscall, 2, CALL_INDIRECT, VOID) /* 247 */
+#endif
+ ENTRY("", 247, no_syscall, 0, CALL_INDIRECT, VOID) /* 247 */
+ ENTRY("", 248, no_syscall, 0, CALL_INDIRECT, VOID) /* 248 */
+ ENTRY("", 249, no_syscall, 0, CALL_INDIRECT, VOID) /* 249 */
+ ENTRY("minherit", SYS_minherit, minherit, 3, CALL_DIRECT, PTR, INT, INT) /* 250 */
+ ENTRY("semsys", SYS_semsys, unimpl_unix_syscall, 5, CALL_INDIRECT, VOID) /* 251 */
+ ENTRY("msgsys", SYS_msgsys, unimpl_unix_syscall, 5, CALL_INDIRECT, VOID) /* 252 */
+ ENTRY("shmsys", SYS_shmsys, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 253 */
+ ENTRY("semctl", SYS_semctl, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 254 */
+ ENTRY("semget", SYS_semget, unimpl_unix_syscall, 3, CALL_INDIRECT, VOID) /* 255 */
+ ENTRY("semop", SYS_semop, unimpl_unix_syscall, 3, CALL_INDIRECT, VOID) /* 256 */
+ ENTRY("", 257, no_syscall, 0, CALL_INDIRECT, VOID) /* 257 */
+ ENTRY("msgctl", SYS_msgctl, unimpl_unix_syscall, 3, CALL_INDIRECT, VOID) /* 258 */
+ ENTRY("msgget", SYS_msgget, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 259 */
+ ENTRY("msgsnd", SYS_msgsnd, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 260 */
+ ENTRY("msgrcv", SYS_msgrcv, unimpl_unix_syscall, 5, CALL_INDIRECT, VOID) /* 261 */
+ ENTRY("shmat", SYS_shmat, unimpl_unix_syscall, 3, CALL_INDIRECT, VOID) /* 262 */
+ ENTRY("shmctl", SYS_shmctl, unimpl_unix_syscall, 3, CALL_INDIRECT, VOID) /* 263 */
+ ENTRY("shmdt", SYS_shmdt, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 264 */
+ ENTRY("shmget", SYS_shmget, unimpl_unix_syscall, 3, CALL_INDIRECT, VOID) /* 265 */
+ ENTRY("shm_open", SYS_shm_open, shm_open, 3, CALL_DIRECT, PTR, INT, INT) /* 266 */
+ ENTRY("shm_unlink", SYS_shm_unlink, shm_unlink, 1, CALL_DIRECT, PTR) /* 267 */
+ ENTRY("sem_open", SYS_sem_open, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 268 */
+ ENTRY("sem_close", SYS_sem_close, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 269 */
+ ENTRY("sem_unlink", SYS_sem_unlink, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 270 */
+ ENTRY("sem_wait", SYS_sem_wait, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 271 */
+ ENTRY("sem_trywait", SYS_sem_trywait, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 272 */
+ ENTRY("sem_post", SYS_sem_post, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 273 */
+ ENTRY("sem_getvalue", SYS_sem_getvalue, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 274 */
+ ENTRY("sem_init", SYS_sem_init, unimpl_unix_syscall, 3, CALL_INDIRECT, VOID) /* 275 */
+ ENTRY("sem_destroy", SYS_sem_destroy, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 276 */
+ ENTRY("open_extended", SYS_open_extended, unimpl_unix_syscall, 6, CALL_INDIRECT, VOID) /* 277 */
+ ENTRY("umask_extended", SYS_umask_extended, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 278 */
+ ENTRY("stat_extended", SYS_stat_extended, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 279 */
+ ENTRY("lstat_extended", SYS_lstat_extended, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 280 */
+ ENTRY("fstat_extended", SYS_fstat_extended, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 281 */
+ ENTRY("chmod_extended", SYS_chmod_extended, unimpl_unix_syscall, 5, CALL_INDIRECT, VOID) /* 282 */
+ ENTRY("fchmod_extended", SYS_fchmod_extended, unimpl_unix_syscall, 5, CALL_INDIRECT, VOID) /* 283 */
+ ENTRY("access_extended", SYS_access_extended, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 284 */
+ ENTRY("settid", SYS_settid, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 285 */
+ ENTRY("gettid", SYS_gettid, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 286 */
+ ENTRY("setsgroups", SYS_setsgroups, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 287 */
+ ENTRY("getsgroups", SYS_getsgroups, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 288 */
+ ENTRY("setwgroups", SYS_setwgroups, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 289 */
+ ENTRY("getwgroups", SYS_getwgroups, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 290 */
+ ENTRY("mkfifo_extended", SYS_mkfifo_extended, unimpl_unix_syscall, 5, CALL_INDIRECT, VOID) /* 291 */
+ ENTRY("mkdir_extended", SYS_mkdir_extended, unimpl_unix_syscall, 5, CALL_INDIRECT, VOID) /* 292 */
+ ENTRY("identitysvc", SYS_identitysvc, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 293 */
+ ENTRY("", 294, no_syscall, 0, CALL_INDIRECT, VOID) /* 294 */
+ ENTRY("", 295, no_syscall, 0, CALL_INDIRECT, VOID) /* 295 */
+ ENTRY("load_shared_file", SYS_load_shared_file, unimpl_unix_syscall, 7, CALL_INDIRECT, VOID) /* 296 */
+ ENTRY("reset_shared_file", SYS_reset_shared_file, unimpl_unix_syscall, 3, CALL_INDIRECT, VOID) /* 297 */
+ ENTRY("new_system_shared_regions", SYS_new_system_shared_regions, unimpl_unix_syscall, 0, CALL_INDIRECT, VOID) /* 298 */
+ ENTRY("shared_region_map_file_np", SYS_shared_region_map_file_np, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 299 */
+ ENTRY("shared_region_make_private_np", SYS_shared_region_make_private_np, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 300 */
+ ENTRY("", 301, no_syscall, 0, CALL_INDIRECT, VOID) /* 301 */
+ ENTRY("", 302, no_syscall, 0, CALL_INDIRECT, VOID) /* 302 */
+ ENTRY("", 303, no_syscall, 0, CALL_INDIRECT, VOID) /* 303 */
+ ENTRY("", 304, no_syscall, 0, CALL_INDIRECT, VOID) /* 304 */
+ ENTRY("", 305, no_syscall, 0, CALL_INDIRECT, VOID) /* 305 */
+ ENTRY("", 306, no_syscall, 0, CALL_INDIRECT, VOID) /* 306 */
+ ENTRY("", 307, no_syscall, 0, CALL_INDIRECT, VOID) /* 307 */
+ ENTRY("", 308, no_syscall, 0, CALL_INDIRECT, VOID) /* 308 */
+ ENTRY("", 309, no_syscall, 0, CALL_INDIRECT, VOID) /* 309 */
+ ENTRY("getsid", SYS_getsid, getsid, 1, CALL_DIRECT, INT) /* 310 */
+ ENTRY("settid_with_pid", SYS_settid_with_pid, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 311 */
+ ENTRY("", 312, no_syscall, 0, CALL_INDIRECT, VOID) /* 312 */
+ ENTRY("aio_fsync", SYS_aio_fsync, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 313 */
+ ENTRY("aio_return", SYS_aio_return, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 314 */
+ ENTRY("aio_suspend", SYS_aio_suspend, unimpl_unix_syscall, 3, CALL_INDIRECT, VOID) /* 315 */
+ ENTRY("aio_cancel", SYS_aio_cancel, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 316 */
+ ENTRY("aio_error", SYS_aio_error, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 317 */
+ ENTRY("aio_read", SYS_aio_read, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 318 */
+ ENTRY("aio_write", SYS_aio_write, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 319 */
+ ENTRY("lio_listio", SYS_lio_listio, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 320 */
+ ENTRY("", 321, no_syscall, 0, CALL_INDIRECT, VOID) /* 321 */
+ ENTRY("", 322, no_syscall, 0, CALL_INDIRECT, VOID) /* 322 */
+ ENTRY("", 323, no_syscall, 0, CALL_INDIRECT, VOID) /* 323 */
+ ENTRY("mlockall", SYS_mlockall, mlockall, 1, CALL_DIRECT, INT) /* 324 */
+ ENTRY("munlockall", SYS_munlockall, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 325 */
+ ENTRY("", 326, no_syscall, 0, CALL_INDIRECT, VOID) /* 326 */
+ ENTRY("issetugid", SYS_issetugid, issetugid, 0, CALL_DIRECT, VOID) /* 327 */
+ ENTRY("__pthread_kill", SYS___pthread_kill, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 328 */
+ ENTRY("pthread_sigmask", SYS_pthread_sigmask, pthread_sigmask, 3, CALL_DIRECT, INT, PTR, PTR) /* 329 */
+ ENTRY("sigwait", SYS_sigwait, sigwait, 2, CALL_DIRECT, PTR, PTR) /* 330 */
+ ENTRY("__disable_threadsignal", SYS___disable_threadsignal, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 331 */
+ ENTRY("__pthread_markcancel", SYS___pthread_markcancel, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 332 */
+ ENTRY("__pthread_canceled", SYS___pthread_canceled, unimpl_unix_syscall, 1, CALL_INDIRECT, VOID) /* 333 */
+ ENTRY("__semwait_signal", SYS___semwait_signal, unimpl_unix_syscall, 6, CALL_INDIRECT, VOID) /* 334 */
+ ENTRY("utrace", SYS_utrace, unimpl_unix_syscall, 2, CALL_INDIRECT, VOID) /* 335 */
+ ENTRY("proc_info", SYS_proc_info, unimpl_unix_syscall, 6, CALL_INDIRECT, VOID) /* 336 */
+ ENTRY("", 337, no_syscall, 0, CALL_INDIRECT, VOID) /* 337 */
+ ENTRY("", 338, no_syscall, 0, CALL_INDIRECT, VOID) /* 338 */
+ ENTRY("", 339, no_syscall, 0, CALL_INDIRECT, VOID) /* 339 */
+ ENTRY("", 340, no_syscall, 0, CALL_INDIRECT, VOID) /* 340 */
+ ENTRY("", 341, no_syscall, 0, CALL_INDIRECT, VOID) /* 341 */
+ ENTRY("", 342, no_syscall, 0, CALL_INDIRECT, VOID) /* 342 */
+ ENTRY("", 343, no_syscall, 0, CALL_INDIRECT, VOID) /* 343 */
+ ENTRY("", 344, no_syscall, 0, CALL_INDIRECT, VOID) /* 344 */
+ ENTRY("", 345, no_syscall, 0, CALL_INDIRECT, VOID) /* 345 */
+ ENTRY("", 346, no_syscall, 0, CALL_INDIRECT, VOID) /* 346 */
+ ENTRY("", 347, no_syscall, 0, CALL_INDIRECT, VOID) /* 347 */
+ ENTRY("", 348, no_syscall, 0, CALL_INDIRECT, VOID) /* 348 */
+ ENTRY("", 349, no_syscall, 0, CALL_INDIRECT, VOID) /* 349 */
+ ENTRY("audit", SYS_audit, audit, 2, CALL_DIRECT, PTR, INT) /* 350 */
+ ENTRY("auditon", SYS_auditon, auditon, 3, CALL_DIRECT, INT, PTR, INT) /* 351 */
+ ENTRY("", 352, no_syscall, 0, CALL_INDIRECT, VOID) /* 352 */
+ ENTRY("getauid", SYS_getauid, getauid, 1, CALL_DIRECT, PTR) /* 353 */
+ ENTRY("setauid", SYS_setauid, setauid, 1, CALL_DIRECT, PTR) /* 354 */
+ ENTRY("getaudit", SYS_getaudit, getaudit, 1, CALL_DIRECT, PTR) /* 355 */
+ ENTRY("setaudit", SYS_setaudit, setaudit, 1, CALL_DIRECT, PTR) /* 356 */
+ ENTRY("getaudit_addr", SYS_getaudit_addr, getaudit_addr, 2, CALL_DIRECT, PTR, INT) /* 357 */
+ ENTRY("setaudit_addr", SYS_setaudit_addr, setaudit_addr, 2, CALL_DIRECT, PTR, INT) /* 358 */
+ ENTRY("auditctl", SYS_auditctl, auditctl, 1, CALL_DIRECT, PTR) /* 359 */
+ ENTRY("", 360, no_syscall, 0, CALL_INDIRECT, VOID) /* 360 */
+ ENTRY("", 361, no_syscall, 0, CALL_INDIRECT, VOID) /* 361 */
+ ENTRY("kqueue", SYS_kqueue, kqueue, 0, CALL_DIRECT, VOID) /* 362 */
+ ENTRY("kevent", SYS_kevent, kevent, 6, CALL_DIRECT, INT, PTR, INT, PTR, INT, PTR) /* 363 */
+ ENTRY("lchown", SYS_lchown, lchown, 3, CALL_DIRECT, PTR, INT , INT) /* 364 */
+ ENTRY("stack_snapshot", SYS_stack_snapshot, unimpl_unix_syscall, 4, CALL_INDIRECT, VOID) /* 365 */
+ ENTRY("", 366, no_syscall, 0, CALL_INDIRECT, VOID) /* 366 */
+ ENTRY("", 367, no_syscall, 0, CALL_INDIRECT, VOID) /* 367 */
+ ENTRY("", 368, no_syscall, 0, CALL_INDIRECT, VOID) /* 368 */
+ ENTRY("", 369, no_syscall, 0, CALL_INDIRECT, VOID) /* 369 */
Modified: trunk/src/host/qemu-neo1973/dis-asm.h
===================================================================
--- trunk/src/host/qemu-neo1973/dis-asm.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/dis-asm.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -181,6 +181,7 @@
#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_2 1
#define bfd_mach_arm_2a 2
@@ -377,6 +378,7 @@
extern int print_insn_v850 PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_tic30 PARAMS ((bfd_vma, disassemble_info*));
extern int print_insn_ppc PARAMS ((bfd_vma, disassemble_info*));
+extern int print_insn_alpha PARAMS ((bfd_vma, disassemble_info*));
#if 0
/* Fetch the disassembler for a given BFD, if that support is available. */
Modified: trunk/src/host/qemu-neo1973/disas.c
===================================================================
--- trunk/src/host/qemu-neo1973/disas.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/disas.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -197,6 +197,9 @@
#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;
#else
fprintf(out, "0x" TARGET_FMT_lx
": Asm output not supported on this arch\n", code);
@@ -255,6 +258,9 @@
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__)
@@ -378,6 +384,9 @@
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)
#ifdef TARGET_PPC64
disasm_info.mach = bfd_mach_ppc64;
Modified: trunk/src/host/qemu-neo1973/dyngen-exec.h
===================================================================
--- trunk/src/host/qemu-neo1973/dyngen-exec.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/dyngen-exec.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -62,6 +62,9 @@
#endif
#endif
+/* XXX: This may be wrong for 64-bit ILP32 hosts. */
+typedef void * host_reg_t;
+
#define INT8_MIN (-128)
#define INT16_MIN (-32767-1)
#define INT32_MIN (-2147483647-1)
@@ -75,27 +78,30 @@
#define UINT32_MAX (4294967295U)
#define UINT64_MAX ((uint64_t)(18446744073709551615))
+#ifdef _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 *, ...);
#undef NULL
#define NULL 0
-#ifdef __i386__
+#if defined(__i386__)
#define AREG0 "ebp"
#define AREG1 "ebx"
#define AREG2 "esi"
#define AREG3 "edi"
-#endif
-#ifdef __x86_64__
-#define AREG0 "rbp"
-#define AREG1 "rbx"
+#elif defined(__x86_64__)
+#define AREG0 "r14"
+#define AREG1 "r15"
#define AREG2 "r12"
#define AREG3 "r13"
-//#define AREG4 "r14"
-//#define AREG5 "r15"
-#endif
-#ifdef __powerpc__
+//#define AREG4 "rbp"
+//#define AREG5 "rbx"
+#elif defined(__powerpc__)
#define AREG0 "r27"
#define AREG1 "r24"
#define AREG2 "r25"
@@ -113,20 +119,22 @@
#endif
#define USE_INT_TO_FLOAT_HELPERS
#define BUGGY_GCC_DIV64
-#endif
-#ifdef __arm__
+#elif defined(__arm__)
#define AREG0 "r7"
#define AREG1 "r4"
#define AREG2 "r5"
#define AREG3 "r6"
-#endif
-#ifdef __mips__
-#define AREG0 "s3"
+#elif defined(__mips__)
+#define AREG0 "fp"
#define AREG1 "s0"
#define AREG2 "s1"
#define AREG3 "s2"
-#endif
-#ifdef __sparc__
+#define AREG4 "s3"
+#define AREG5 "s4"
+#define AREG6 "s5"
+#define AREG7 "s6"
+#define AREG8 "s7"
+#elif defined(__sparc__)
#ifdef HOST_SOLARIS
#define AREG0 "g2"
#define AREG1 "g3"
@@ -155,14 +163,12 @@
#endif
#endif
#define USE_FP_CONVERT
-#endif
-#ifdef __s390__
+#elif defined(__s390__)
#define AREG0 "r10"
#define AREG1 "r7"
#define AREG2 "r8"
#define AREG3 "r9"
-#endif
-#ifdef __alpha__
+#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"
@@ -172,19 +178,19 @@
#define AREG4 "$12"
#define AREG5 "$13"
#define AREG6 "$14"
-#endif
-#ifdef __mc68000
+#elif defined(__mc68000)
#define AREG0 "%a5"
#define AREG1 "%a4"
#define AREG2 "%d7"
#define AREG3 "%d6"
#define AREG4 "%d5"
-#endif
-#ifdef __ia64__
+#elif defined(__ia64__)
#define AREG0 "r7"
#define AREG1 "r4"
#define AREG2 "r5"
#define AREG3 "r6"
+#else
+#error unsupported CPU
#endif
/* force GCC to generate only one epilog at the end of the function */
@@ -237,40 +243,37 @@
#define ASM_NAME(x) #x
#endif
-#ifdef __i386__
+#if defined(__i386__)
#define EXIT_TB() asm volatile ("ret")
#define GOTO_LABEL_PARAM(n) asm volatile ("jmp " ASM_NAME(__op_gen_label) #n)
-#endif
-#ifdef __x86_64__
+#elif defined(__x86_64__)
#define EXIT_TB() asm volatile ("ret")
#define GOTO_LABEL_PARAM(n) asm volatile ("jmp " ASM_NAME(__op_gen_label) #n)
-#endif
-#ifdef __powerpc__
+#elif defined(__powerpc__)
#define EXIT_TB() asm volatile ("blr")
#define GOTO_LABEL_PARAM(n) asm volatile ("b " ASM_NAME(__op_gen_label) #n)
-#endif
-#ifdef __s390__
+#elif defined(__s390__)
#define EXIT_TB() asm volatile ("br %r14")
#define GOTO_LABEL_PARAM(n) asm volatile ("b " ASM_NAME(__op_gen_label) #n)
-#endif
-#ifdef __alpha__
+#elif defined(__alpha__)
#define EXIT_TB() asm volatile ("ret")
-#endif
-#ifdef __ia64__
+#elif defined(__ia64__)
#define EXIT_TB() asm volatile ("br.ret.sptk.many b0;;")
#define GOTO_LABEL_PARAM(n) asm volatile ("br.sptk.many " \
ASM_NAME(__op_gen_label) #n)
-#endif
-#ifdef __sparc__
+#elif defined(__sparc__)
#define EXIT_TB() asm volatile ("jmpl %i0 + 8, %g0; nop")
#define GOTO_LABEL_PARAM(n) asm volatile ("ba " ASM_NAME(__op_gen_label) #n ";nop")
-#endif
-#ifdef __arm__
+#elif defined(__arm__)
#define EXIT_TB() asm volatile ("b exec_loop")
#define GOTO_LABEL_PARAM(n) asm volatile ("b " ASM_NAME(__op_gen_label) #n)
-#endif
-#ifdef __mc68000
+#elif defined(__mc68000)
#define EXIT_TB() asm volatile ("rts")
+#elif defined(__mips__)
+#define EXIT_TB() asm volatile ("jr $ra")
+#define GOTO_LABEL_PARAM(n) asm volatile (".set noat; la $1, " ASM_NAME(__op_gen_label) #n "; jr $1; .set at")
+#else
+#error unsupported CPU
#endif
#endif /* !defined(__DYNGEN_EXEC_H__) */
Modified: trunk/src/host/qemu-neo1973/dyngen.c
===================================================================
--- trunk/src/host/qemu-neo1973/dyngen.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/dyngen.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -117,6 +117,21 @@
#define elf_check_arch(x) ((x) == EM_68K)
#define ELF_USES_RELOCA
+#elif defined(HOST_MIPS)
+
+#define ELF_CLASS ELFCLASS32
+#define ELF_ARCH EM_MIPS
+#define elf_check_arch(x) ((x) == EM_MIPS)
+#define ELF_USES_RELOC
+
+#elif defined(HOST_MIPS64)
+
+/* Assume n32 ABI here, which is ELF32. */
+#define ELF_CLASS ELFCLASS32
+#define ELF_ARCH EM_MIPS
+#define elf_check_arch(x) ((x) == EM_MIPS)
+#define ELF_USES_RELOCA
+
#else
#error unsupported CPU - please update the code
#endif
@@ -148,11 +163,11 @@
#ifdef CONFIG_FORMAT_COFF
-#include "a.out.h"
-
typedef int32_t host_long;
typedef uint32_t host_ulong;
+#include "a.out.h"
+
#define FILENAMELEN 256
typedef struct coff_sym {
@@ -1641,6 +1656,26 @@
error("rts expected at the end of %s", name);
copy_size = p - p_start;
}
+#elif defined(HOST_MIPS) || defined(HOST_MIPS64)
+ {
+#define INSN_RETURN 0x03e00008
+#define INSN_NOP 0x00000000
+
+ uint8_t *p = p_end;
+
+ if (p < (p_start + 0x8)) {
+ error("empty code for %s", name);
+ } else {
+ uint32_t end_insn1, end_insn2;
+
+ p -= 0x8;
+ end_insn1 = get32((uint32_t *)(p + 0x0));
+ end_insn2 = get32((uint32_t *)(p + 0x4));
+ if (end_insn1 != INSN_RETURN && end_insn2 != INSN_NOP)
+ error("jr ra not found at end of %s", name);
+ }
+ copy_size = p - p_start;
+ }
#else
#error unsupported CPU
#endif
@@ -1715,8 +1750,9 @@
}
#endif
#if defined(__APPLE__)
-/* set __attribute((unused)) on darwin because we wan't to avoid warning when we don't use the symbol */
- fprintf(outfile, "extern char %s __attribute__((unused));\n", sym_name);
+ /* Set __attribute((unused)) on darwin because we
+ want to avoid warning when we don't use the symbol. */
+ fprintf(outfile, " extern char %s __attribute__((unused));\n", sym_name);
#elif defined(HOST_IA64)
if (ELF64_R_TYPE(rel->r_info) != R_IA64_PCREL21B)
/*
@@ -1740,7 +1776,7 @@
{
EXE_SYM *sym;
const char *sym_name, *p;
- unsigned long val;
+ host_ulong val;
int n;
for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
@@ -1772,7 +1808,7 @@
#ifdef CONFIG_FORMAT_MACH
offset -= section_hdr[sym->n_sect-1].addr;
#endif
- val = *(unsigned long *)(ptr + offset);
+ val = *(host_ulong *)(ptr + offset);
#ifdef ELF_USES_RELOCA
{
int reloc_shndx, nb_relocs1, j;
@@ -1801,7 +1837,7 @@
}
}
- /* load parameres in variables */
+ /* load parameters in variables */
for(i = 0; i < nb_args; i++) {
fprintf(outfile, " param%d = *opparam_ptr++;\n", i + 1);
}
@@ -2349,6 +2385,33 @@
reloc_offset, reloc_offset, name, addend,
reloc_offset);
break;
+ case R_SPARC_HH22:
+ fprintf(outfile,
+ " *(uint32_t *)(gen_code_ptr + %d) = "
+ "((*(uint32_t *)(gen_code_ptr + %d)) "
+ " & ~0x00000000) "
+ " | (((%s + %d) >> 42) & 0x00000000);\n",
+ reloc_offset, reloc_offset, name, addend);
+ break;
+
+ case R_SPARC_LM22:
+ fprintf(outfile,
+ " *(uint32_t *)(gen_code_ptr + %d) = "
+ "((*(uint32_t *)(gen_code_ptr + %d)) "
+ " & ~0x00000000) "
+ " | (((%s + %d) >> 10) & 0x00000000);\n",
+ reloc_offset, reloc_offset, name, addend);
+ break;
+
+ case R_SPARC_HM10:
+ fprintf(outfile,
+ " *(uint32_t *)(gen_code_ptr + %d) = "
+ "((*(uint32_t *)(gen_code_ptr + %d)) "
+ " & ~0x00000000) "
+ " | ((((%s + %d) >> 32 & 0x3ff)) & 0x00000000);\n",
+ reloc_offset, reloc_offset, name, addend);
+ break;
+
default:
error("unsupported sparc64 relocation (%d) for symbol %s", type, name);
}
@@ -2456,6 +2519,81 @@
}
}
}
+#elif defined(HOST_MIPS) || defined(HOST_MIPS64)
+ {
+ for (i = 0, rel = relocs; i < nb_relocs; i++, rel++) {
+ if (rel->r_offset >= start_offset && rel->r_offset < start_offset + copy_size) {
+ char name[256];
+ int type;
+ int addend;
+ int reloc_offset;
+
+ sym_name = strtab + symtab[ELF32_R_SYM(rel->r_info)].st_name;
+ /* the compiler leave some unnecessary references to the code */
+ if (sym_name[0] == '\0')
+ continue;
+ get_reloc_expr(name, sizeof(name), sym_name);
+ type = ELF32_R_TYPE(rel->r_info);
+ addend = get32((uint32_t *)(text + rel->r_offset));
+ reloc_offset = rel->r_offset - start_offset;
+ switch (type) {
+ case R_MIPS_26:
+ fprintf(outfile, " /* R_MIPS_26 RELOC, offset 0x%x, name %s */\n",
+ rel->r_offset, sym_name);
+ fprintf(outfile,
+ " *(uint32_t *)(gen_code_ptr + 0x%x) = "
+ "(0x%x & ~0x3fffff) "
+ "| ((0x%x + ((%s - (*(uint32_t *)(gen_code_ptr + 0x%x))) >> 2)) "
+ " & 0x3fffff);\n",
+ reloc_offset, addend, addend, name, reloc_offset);
+ break;
+ case R_MIPS_HI16:
+ fprintf(outfile, " /* R_MIPS_HI16 RELOC, offset 0x%x, name %s */\n",
+ rel->r_offset, sym_name);
+ fprintf(outfile,
+ " *(uint32_t *)(gen_code_ptr + 0x%x) = "
+ "((*(uint32_t *)(gen_code_ptr + 0x%x)) "
+ " & ~0xffff) "
+ " | (((%s - 0x8000) >> 16) & 0xffff);\n",
+ reloc_offset, reloc_offset, name);
+ break;
+ case R_MIPS_LO16:
+ fprintf(outfile, " /* R_MIPS_LO16 RELOC, offset 0x%x, name %s */\n",
+ rel->r_offset, sym_name);
+ fprintf(outfile,
+ " *(uint32_t *)(gen_code_ptr + 0x%x) = "
+ "((*(uint32_t *)(gen_code_ptr + 0x%x)) "
+ " & ~0xffff) "
+ " | (%s & 0xffff);\n",
+ reloc_offset, reloc_offset, name);
+ break;
+ case R_MIPS_PC16:
+ fprintf(outfile, " /* R_MIPS_PC16 RELOC, offset 0x%x, name %s */\n",
+ rel->r_offset, sym_name);
+ fprintf(outfile,
+ " *(uint32_t *)(gen_code_ptr + 0x%x) = "
+ "(0x%x & ~0xffff) "
+ "| ((0x%x + ((%s - (*(uint32_t *)(gen_code_ptr + 0x%x))) >> 2)) "
+ " & 0xffff);\n",
+ reloc_offset, addend, addend, name, reloc_offset);
+ break;
+ case R_MIPS_GOT16:
+ case R_MIPS_CALL16:
+ fprintf(outfile, " /* R_MIPS_GOT16 RELOC, offset 0x%x, name %s */\n",
+ rel->r_offset, sym_name);
+ fprintf(outfile,
+ " *(uint32_t *)(gen_code_ptr + 0x%x) = "
+ "((*(uint32_t *)(gen_code_ptr + 0x%x)) "
+ " & ~0xffff) "
+ " | (((%s - 0x8000) >> 16) & 0xffff);\n",
+ reloc_offset, reloc_offset, name);
+ break;
+ default:
+ error("unsupported MIPS relocation (%d)", type);
+ }
+ }
+ }
+ }
#else
#error unsupported CPU
#endif
Modified: trunk/src/host/qemu-neo1973/dyngen.h
===================================================================
--- trunk/src/host/qemu-neo1973/dyngen.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/dyngen.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -28,37 +28,21 @@
#endif
int __op_jmp0, __op_jmp1, __op_jmp2, __op_jmp3;
-#ifdef __i386__
+#if defined(__i386__) || defined(__x86_64__) || defined(__s390__)
static inline void flush_icache_range(unsigned long start, unsigned long stop)
{
}
-#endif
-
-#ifdef __x86_64__
+#elif defined(__ia64__)
static inline void flush_icache_range(unsigned long start, unsigned long stop)
{
-}
-#endif
-
-#ifdef __s390__
-static inline void flush_icache_range(unsigned long start, unsigned long stop)
-{
-}
-#endif
-
-#ifdef __ia64__
-static inline void flush_icache_range(unsigned long start, unsigned long stop)
-{
while (start < stop) {
asm volatile ("fc %0" :: "r"(start));
start += 32;
}
asm volatile (";;sync.i;;srlz.i;;");
}
-#endif
+#elif defined(__powerpc__)
-#ifdef __powerpc__
-
#define MIN_CACHE_LINE_SIZE 8 /* conservative value */
static void inline flush_icache_range(unsigned long start, unsigned long stop)
@@ -78,17 +62,12 @@
asm volatile ("sync" : : : "memory");
asm volatile ("isync" : : : "memory");
}
-#endif
-
-#ifdef __alpha__
+#elif defined(__alpha__)
static inline void flush_icache_range(unsigned long start, unsigned long stop)
{
asm ("imb");
}
-#endif
-
-#ifdef __sparc__
-
+#elif defined(__sparc__)
static void inline flush_icache_range(unsigned long start, unsigned long stop)
{
unsigned long p;
@@ -99,10 +78,7 @@
for (; p < stop; p += 8)
__asm__ __volatile__("flush\t%0" : : "r" (p));
}
-
-#endif
-
-#ifdef __arm__
+#elif defined(__arm__)
static inline void flush_icache_range(unsigned long start, unsigned long stop)
{
register unsigned long _beg __asm ("a1") = start;
@@ -110,14 +86,22 @@
register unsigned long _flg __asm ("a3") = 0;
__asm __volatile__ ("swi 0x9f0002" : : "r" (_beg), "r" (_end), "r" (_flg));
}
-#endif
+#elif defined(__mc68000)
-#ifdef __mc68000
-#include <asm/cachectl.h>
+# include <asm/cachectl.h>
static inline void flush_icache_range(unsigned long start, unsigned long stop)
{
cacheflush(start,FLUSH_SCOPE_LINE,FLUSH_CACHE_BOTH,stop-start+16);
}
+#elif defined(__mips__)
+
+#include <sys/cachectl.h>
+static inline void flush_icache_range(unsigned long start, unsigned long stop)
+{
+ _flush_cache ((void *)start, stop - start, BCACHE);
+}
+#else
+#error unsupported CPU
#endif
#ifdef __alpha__
@@ -248,7 +232,6 @@
#ifdef __ia64
-
/* Patch instruction with "val" where "mask" has 1 bits. */
static inline void ia64_patch (uint64_t insn_addr, uint64_t mask, uint64_t val)
{
Modified: trunk/src/host/qemu-neo1973/ecc.h
===================================================================
--- trunk/src/host/qemu-neo1973/ecc.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/ecc.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -5,7 +5,7 @@
* Copyright (c) 2006 Openedhand Ltd.
* Written by Andrzej Zaborowski <balrog at zabor.org>
*
- * This code is licensed under the GPLv2.
+ * This code is licensed under the GNU GPL v2.
*/
struct ecc_state_s {
Modified: trunk/src/host/qemu-neo1973/elf.h
===================================================================
--- trunk/src/host/qemu-neo1973/elf.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/elf.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -328,6 +328,9 @@
#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
Modified: trunk/src/host/qemu-neo1973/elf_ops.h
===================================================================
--- trunk/src/host/qemu-neo1973/elf_ops.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/elf_ops.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -139,11 +139,13 @@
}
int glue(load_elf, SZ)(int fd, int64_t virt_to_phys_addend,
- int must_swab, uint64_t *pentry)
+ int must_swab, uint64_t *pentry,
+ uint64_t *lowaddr, uint64_t *highaddr)
{
struct elfhdr ehdr;
struct elf_phdr *phdr = NULL, *ph;
int size, i, total_size;
+ elf_word low = 0, high = 0;
elf_word mem_size, addr;
uint8_t *data = NULL;
@@ -193,12 +195,20 @@
cpu_physical_memory_write_rom(addr, data, mem_size);
total_size += mem_size;
+ if (!low || addr < low)
+ low = addr;
+ if (!high || (addr + mem_size) > high)
+ high = addr + mem_size;
qemu_free(data);
data = NULL;
}
}
qemu_free(phdr);
+ if (lowaddr)
+ *lowaddr = (uint64_t)low;
+ if (highaddr)
+ *highaddr = (uint64_t)high;
return total_size;
fail:
qemu_free(data);
Modified: trunk/src/host/qemu-neo1973/exec-all.h
===================================================================
--- trunk/src/host/qemu-neo1973/exec-all.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/exec-all.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -357,7 +357,7 @@
extern CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
extern void *io_mem_opaque[IO_MEM_NB_ENTRIES];
-#ifdef __powerpc__
+#if defined(__powerpc__)
static inline int testandset (int *p)
{
int ret;
@@ -373,9 +373,7 @@
: "cr0", "memory");
return ret;
}
-#endif
-
-#ifdef __i386__
+#elif defined(__i386__)
static inline int testandset (int *p)
{
long int readval = 0;
@@ -386,9 +384,7 @@
: "cc");
return readval;
}
-#endif
-
-#ifdef __x86_64__
+#elif defined(__x86_64__)
static inline int testandset (int *p)
{
long int readval = 0;
@@ -399,9 +395,7 @@
: "cc");
return readval;
}
-#endif
-
-#ifdef __s390__
+#elif defined(__s390__)
static inline int testandset (int *p)
{
int ret;
@@ -413,9 +407,7 @@
: "cc", "memory" );
return ret;
}
-#endif
-
-#ifdef __alpha__
+#elif defined(__alpha__)
static inline int testandset (int *p)
{
int ret;
@@ -432,9 +424,7 @@
: "m" (*p));
return ret;
}
-#endif
-
-#ifdef __sparc__
+#elif defined(__sparc__)
static inline int testandset (int *p)
{
int ret;
@@ -446,9 +436,7 @@
return (ret ? 1 : 0);
}
-#endif
-
-#ifdef __arm__
+#elif defined(__arm__)
static inline int testandset (int *spinlock)
{
register unsigned int ret;
@@ -458,9 +446,7 @@
return ret;
}
-#endif
-
-#ifdef __mc68000
+#elif defined(__mc68000)
static inline int testandset (int *p)
{
char ret;
@@ -470,15 +456,36 @@
: "cc","memory");
return ret;
}
-#endif
+#elif defined(__ia64)
-#ifdef __ia64
#include <ia64intrin.h>
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"
+ " bnez $1, 1b \n"
+ " .set pop "
+ : "=r" (ret), "+R" (*p)
+ :
+ : "memory");
+
+ return ret;
+}
+#else
+#error unimplemented CPU support
#endif
typedef int spinlock_t;
@@ -572,6 +579,8 @@
is_user = ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR);
#elif defined (TARGET_SH4)
is_user = ((env->sr & SR_MD) == 0);
+#elif defined (TARGET_ALPHA)
+ is_user = ((env->ps >> 3) & 3);
#else
#error unimplemented CPU
#endif
@@ -581,13 +590,12 @@
}
pd = env->tlb_table[is_user][index].addr_code & ~TARGET_PAGE_MASK;
if (pd > IO_MEM_ROM && !(pd & IO_MEM_ROMD)) {
- cpu_abort(env, "Trying to execute code outside RAM or ROM at 0x%08lx\n", addr);
+ cpu_abort(env, "Trying to execute code outside RAM or ROM at 0x" TARGET_FMT_lx "\n", addr);
}
return addr + env->tlb_table[is_user][index].addend - (unsigned long)phys_ram_base;
}
#endif
-
#ifdef USE_KQEMU
#define KQEMU_MODIFY_PAGE_MASK (0xff & ~(VGA_DIRTY_FLAG | CODE_DIRTY_FLAG))
Modified: trunk/src/host/qemu-neo1973/exec.c
===================================================================
--- trunk/src/host/qemu-neo1973/exec.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/exec.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -47,6 +47,8 @@
//#define DEBUG_TB_CHECK
//#define DEBUG_TLB_CHECK
+//#define DEBUG_IOPORT
+
#if !defined(CONFIG_USER_ONLY)
/* TB consistency checks only implemented for usermode emulation. */
#undef DEBUG_TB_CHECK
@@ -62,6 +64,9 @@
#if defined(TARGET_SPARC64)
#define TARGET_PHYS_ADDR_SPACE_BITS 41
+#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
#else
@@ -82,6 +87,7 @@
int phys_ram_fd;
uint8_t *phys_ram_base;
uint8_t *phys_ram_dirty;
+static ram_addr_t phys_ram_alloc_offset = 0;
CPUState *first_cpu;
/* current CPU in the current thread. It is only valid inside
@@ -106,7 +112,15 @@
} 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)
@@ -127,6 +141,9 @@
CPUReadMemoryFunc *io_mem_read[IO_MEM_NB_ENTRIES][4];
void *io_mem_opaque[IO_MEM_NB_ENTRIES];
static int io_mem_nb;
+#if defined(CONFIG_SOFTMMU)
+static int io_mem_watch;
+#endif
/* log support */
char *logfilename = "/tmp/qemu.log";
@@ -273,6 +290,7 @@
cpu_index++;
}
env->cpu_index = cpu_index;
+ env->nb_watchpoints = 0;
*penv = env;
}
@@ -331,7 +349,7 @@
#ifdef DEBUG_TB_CHECK
-static void tb_invalidate_check(unsigned long address)
+static void tb_invalidate_check(target_ulong address)
{
TranslationBlock *tb;
int i;
@@ -1012,7 +1030,8 @@
#if defined(TARGET_HAS_ICE)
static void breakpoint_invalidate(CPUState *env, target_ulong pc)
{
- target_ulong addr, pd;
+ target_phys_addr_t addr;
+ target_ulong pd;
ram_addr_t ram_addr;
PhysPageDesc *p;
@@ -1028,6 +1047,44 @@
}
#endif
+/* Add a watchpoint. */
+int cpu_watchpoint_insert(CPUState *env, target_ulong addr)
+{
+ int i;
+
+ for (i = 0; i < env->nb_watchpoints; i++) {
+ if (addr == env->watchpoint[i].vaddr)
+ return 0;
+ }
+ if (env->nb_watchpoints >= MAX_WATCHPOINTS)
+ return -1;
+
+ i = env->nb_watchpoints++;
+ env->watchpoint[i].vaddr = addr;
+ tlb_flush_page(env, addr);
+ /* FIXME: This flush is needed because of the hack to make memory ops
+ terminate the TB. It can be removed once the proper IO trap and
+ re-execute bits are in. */
+ tb_flush(env);
+ return i;
+}
+
+/* Remove a watchpoint. */
+int cpu_watchpoint_remove(CPUState *env, target_ulong addr)
+{
+ int i;
+
+ for (i = 0; i < env->nb_watchpoints; i++) {
+ if (addr == env->watchpoint[i].vaddr) {
+ env->nb_watchpoints--;
+ env->watchpoint[i] = env->watchpoint[env->nb_watchpoints];
+ tlb_flush_page(env, addr);
+ return 0;
+ }
+ }
+ return -1;
+}
+
/* add a breakpoint. EXCP_DEBUG is returned by the CPU loop if a
breakpoint is reached */
int cpu_breakpoint_insert(CPUState *env, target_ulong pc)
@@ -1221,6 +1278,18 @@
abort();
}
+CPUState *cpu_copy(CPUState *env)
+{
+ CPUState *new_env = cpu_init();
+ /* preserve chaining and index */
+ CPUState *next_cpu = new_env->next_cpu;
+ int cpu_index = new_env->cpu_index;
+ memcpy(new_env, env, sizeof(CPUState));
+ new_env->next_cpu = next_cpu;
+ new_env->cpu_index = cpu_index;
+ return new_env;
+}
+
#if !defined(CONFIG_USER_ONLY)
/* NOTE: if flush_global is true, also flush global entries (not
@@ -1243,6 +1312,16 @@
env->tlb_table[1][i].addr_read = -1;
env->tlb_table[1][i].addr_write = -1;
env->tlb_table[1][i].addr_code = -1;
+#if (NB_MMU_MODES >= 3)
+ env->tlb_table[2][i].addr_read = -1;
+ env->tlb_table[2][i].addr_write = -1;
+ env->tlb_table[2][i].addr_code = -1;
+#if (NB_MMU_MODES == 4)
+ env->tlb_table[3][i].addr_read = -1;
+ env->tlb_table[3][i].addr_write = -1;
+ env->tlb_table[3][i].addr_code = -1;
+#endif
+#endif
}
memset (env->tb_jmp_cache, 0, TB_JMP_CACHE_SIZE * sizeof (void *));
@@ -1288,6 +1367,12 @@
i = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
tlb_flush_entry(&env->tlb_table[0][i], addr);
tlb_flush_entry(&env->tlb_table[1][i], addr);
+#if (NB_MMU_MODES >= 3)
+ tlb_flush_entry(&env->tlb_table[2][i], addr);
+#if (NB_MMU_MODES == 4)
+ tlb_flush_entry(&env->tlb_table[3][i], addr);
+#endif
+#endif
/* Discard jump cache entries for any tb which might potentially
overlap the flushed page. */
@@ -1377,6 +1462,14 @@
tlb_reset_dirty_range(&env->tlb_table[0][i], start1, length);
for(i = 0; i < CPU_TLB_SIZE; i++)
tlb_reset_dirty_range(&env->tlb_table[1][i], start1, length);
+#if (NB_MMU_MODES >= 3)
+ for(i = 0; i < CPU_TLB_SIZE; i++)
+ tlb_reset_dirty_range(&env->tlb_table[2][i], start1, length);
+#if (NB_MMU_MODES == 4)
+ for(i = 0; i < CPU_TLB_SIZE; i++)
+ tlb_reset_dirty_range(&env->tlb_table[3][i], start1, length);
+#endif
+#endif
}
#if !defined(CONFIG_SOFTMMU)
@@ -1429,6 +1522,14 @@
tlb_update_dirty(&env->tlb_table[0][i]);
for(i = 0; i < CPU_TLB_SIZE; i++)
tlb_update_dirty(&env->tlb_table[1][i]);
+#if (NB_MMU_MODES >= 3)
+ for(i = 0; i < CPU_TLB_SIZE; i++)
+ tlb_update_dirty(&env->tlb_table[2][i]);
+#if (NB_MMU_MODES == 4)
+ for(i = 0; i < CPU_TLB_SIZE; i++)
+ tlb_update_dirty(&env->tlb_table[3][i]);
+#endif
+#endif
}
static inline void tlb_set_dirty1(CPUTLBEntry *tlb_entry,
@@ -1454,6 +1555,12 @@
i = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
tlb_set_dirty1(&env->tlb_table[0][i], addr);
tlb_set_dirty1(&env->tlb_table[1][i], addr);
+#if (NB_MMU_MODES >= 3)
+ tlb_set_dirty1(&env->tlb_table[2][i], addr);
+#if (NB_MMU_MODES == 4)
+ tlb_set_dirty1(&env->tlb_table[3][i], addr);
+#endif
+#endif
}
/* add a new TLB entry. At most one entry for a given virtual address
@@ -1471,6 +1578,7 @@
target_phys_addr_t addend;
int ret;
CPUTLBEntry *te;
+ int i;
p = phys_page_find(paddr >> TARGET_PAGE_BITS);
if (!p) {
@@ -1497,6 +1605,22 @@
address = vaddr;
addend = (unsigned long)phys_ram_base + (pd & TARGET_PAGE_MASK);
}
+
+ /* Make accesses to pages with watchpoints go via the
+ watchpoint trap routines. */
+ for (i = 0; i < env->nb_watchpoints; i++) {
+ if (vaddr == (env->watchpoint[i].vaddr & TARGET_PAGE_MASK)) {
+ if (address & ~TARGET_PAGE_MASK) {
+ env->watchpoint[i].is_ram = 0;
+ address = vaddr | io_mem_watch;
+ } else {
+ env->watchpoint[i].is_ram = 1;
+ /* TODO: Figure out how to make read watchpoints coexist
+ with code. */
+ pd = (pd & TARGET_PAGE_MASK) | io_mem_watch | IO_MEM_ROMD;
+ }
+ }
+ }
index = (vaddr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
addend -= vaddr;
@@ -1812,11 +1936,33 @@
return p->phys_offset;
}
+/* XXX: better than nothing */
+ram_addr_t qemu_ram_alloc(unsigned int size)
+{
+ ram_addr_t addr;
+ if ((phys_ram_alloc_offset + size) >= phys_ram_size) {
+ fprintf(stderr, "Not enough memory (requested_size = %u, max memory = %d)\n",
+ size, phys_ram_size);
+ abort();
+ }
+ addr = phys_ram_alloc_offset;
+ phys_ram_alloc_offset = TARGET_PAGE_ALIGN(phys_ram_alloc_offset + size);
+ return addr;
+}
+
+void qemu_ram_free(ram_addr_t addr)
+{
+}
+
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);
#endif
+#ifdef TARGET_SPARC
+ // Not enabled yet because of bugs in gdbstub etc.
+ //raise_exception(TT_DATA_ACCESS);
+#endif
return 0;
}
@@ -1825,6 +1971,10 @@
#ifdef DEBUG_UNASSIGNED
printf("Unassigned mem write 0x%08x = 0x%x\n", (int)addr, val);
#endif
+#ifdef TARGET_SPARC
+ // Not enabled yet because of bugs in gdbstub etc.
+ //raise_exception(TT_DATA_ACCESS);
+#endif
}
static CPUReadMemoryFunc *unassigned_mem_read[3] = {
@@ -1929,6 +2079,85 @@
notdirty_mem_writel,
};
+#if defined(CONFIG_SOFTMMU)
+/* 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)
+{
+ return ldub_phys(addr);
+}
+
+static uint32_t watch_mem_readw(void *opaque, target_phys_addr_t addr)
+{
+ return lduw_phys(addr);
+}
+
+static uint32_t watch_mem_readl(void *opaque, target_phys_addr_t addr)
+{
+ return ldl_phys(addr);
+}
+
+/* Generate a debug exception if a watchpoint has been hit.
+ Returns the real physical address of the access. addr will be a host
+ address in the is_ram case. */
+static target_ulong check_watchpoint(target_phys_addr_t addr)
+{
+ CPUState *env = cpu_single_env;
+ target_ulong watch;
+ target_ulong retaddr;
+ int i;
+
+ retaddr = addr;
+ for (i = 0; i < env->nb_watchpoints; i++) {
+ watch = env->watchpoint[i].vaddr;
+ if (((env->mem_write_vaddr ^ watch) & TARGET_PAGE_MASK) == 0) {
+ if (env->watchpoint[i].is_ram)
+ retaddr = addr - (unsigned long)phys_ram_base;
+ if (((addr ^ watch) & ~TARGET_PAGE_MASK) == 0) {
+ cpu_single_env->watchpoint_hit = i + 1;
+ cpu_interrupt(cpu_single_env, CPU_INTERRUPT_DEBUG);
+ break;
+ }
+ }
+ }
+ return retaddr;
+}
+
+static void watch_mem_writeb(void *opaque, target_phys_addr_t addr,
+ uint32_t val)
+{
+ addr = check_watchpoint(addr);
+ stb_phys(addr, val);
+}
+
+static void watch_mem_writew(void *opaque, target_phys_addr_t addr,
+ uint32_t val)
+{
+ addr = check_watchpoint(addr);
+ stw_phys(addr, val);
+}
+
+static void watch_mem_writel(void *opaque, target_phys_addr_t addr,
+ uint32_t val)
+{
+ addr = check_watchpoint(addr);
+ stl_phys(addr, val);
+}
+
+static CPUReadMemoryFunc *watch_mem_read[3] = {
+ watch_mem_readb,
+ watch_mem_readw,
+ watch_mem_readl,
+};
+
+static CPUWriteMemoryFunc *watch_mem_write[3] = {
+ watch_mem_writeb,
+ watch_mem_writew,
+ watch_mem_writel,
+};
+#endif
+
static void io_mem_init(void)
{
cpu_register_io_memory(IO_MEM_ROM >> IO_MEM_SHIFT, error_mem_read, unassigned_mem_write, NULL);
@@ -1936,6 +2165,10 @@
cpu_register_io_memory(IO_MEM_NOTDIRTY >> IO_MEM_SHIFT, error_mem_read, notdirty_mem_write, NULL);
io_mem_nb = 5;
+#if defined(CONFIG_SOFTMMU)
+ io_mem_watch = cpu_register_io_memory(-1, watch_mem_read,
+ watch_mem_write, NULL);
+#endif
/* 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);
@@ -2258,6 +2491,36 @@
}
}
+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);
+#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 = phys_ram_base + (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)
{
@@ -2320,7 +2583,8 @@
uint8_t *buf, int len, int is_write)
{
int l;
- target_ulong page, phys_addr;
+ target_phys_addr_t phys_addr;
+ target_ulong page;
while (len > 0) {
page = addr & TARGET_PAGE_MASK;
Modified: trunk/src/host/qemu-neo1973/fpu/softfloat-native.c
===================================================================
--- trunk/src/host/qemu-neo1973/fpu/softfloat-native.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/fpu/softfloat-native.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -30,7 +30,26 @@
#define sqrtf(f) ((float)sqrt(f))
#define remainderf(fa, fb) ((float)remainder(fa, fb))
#define rintf(f) ((float)rint(f))
+#if !defined(__sparc__) && defined(HOST_SOLARIS) && HOST_SOLARIS < 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(__powerpc__)
@@ -59,11 +78,21 @@
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)
{
@@ -74,10 +103,18 @@
{
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)
{
@@ -132,6 +169,37 @@
}
#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.
*----------------------------------------------------------------------------*/
@@ -218,9 +286,62 @@
}
#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(HOST_SOLARIS) && HOST_SOLARIS < 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);
Modified: trunk/src/host/qemu-neo1973/fpu/softfloat-native.h
===================================================================
--- trunk/src/host/qemu-neo1973/fpu/softfloat-native.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/fpu/softfloat-native.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -15,7 +15,7 @@
* Solaris 10 with GCC4 does not need these macros as they
* are defined in <iso/math_c99.h> with a compiler directive
*/
-#if defined(HOST_SOLARIS) && (( HOST_SOLARIS <= 9 ) || ( ( HOST_SOLARIS >= 10 ) && ( __GNUC__ <= 4) ))
+#if defined(HOST_SOLARIS) && (( HOST_SOLARIS <= 9 ) || ((HOST_SOLARIS >= 10) && (__GNUC__ <= 4)))
/*
* C99 7.12.3 classification macros
* and
@@ -33,6 +33,29 @@
#define isunordered(x,y) unordered(x, y)
#endif
+#if defined(__sun__) && !defined(NEED_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
@@ -99,7 +122,9 @@
| 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
@@ -107,7 +132,9 @@
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
@@ -120,6 +147,8 @@
*----------------------------------------------------------------------------*/
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);
@@ -200,8 +229,12 @@
*----------------------------------------------------------------------------*/
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 );
Modified: trunk/src/host/qemu-neo1973/fpu/softfloat.c
===================================================================
--- trunk/src/host/qemu-neo1973/fpu/softfloat.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/fpu/softfloat.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -1164,6 +1164,27 @@
}
+float32 uint64_to_float32( uint64 a STATUS_PARAM )
+{
+ int8 shiftCount;
+
+ if ( a == 0 ) return 0;
+ shiftCount = countLeadingZeros64( a ) - 40;
+ if ( 0 <= shiftCount ) {
+ return packFloat32( 1 > 0, 0x95 - shiftCount, a<<shiftCount );
+ }
+ else {
+ shiftCount += 7;
+ if ( shiftCount < 0 ) {
+ shift64RightJamming( a, - shiftCount, &a );
+ }
+ else {
+ a <<= shiftCount;
+ }
+ return roundAndPackFloat32( 1 > 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
@@ -1183,6 +1204,13 @@
}
+float64 uint64_to_float64( uint64 a STATUS_PARAM )
+{
+ if ( a == 0 ) return 0;
+ return normalizeRoundAndPackFloat64( 0, 0x43C, a STATUS_VAR );
+
+}
+
#ifdef FLOATX80
/*----------------------------------------------------------------------------
@@ -5282,6 +5310,26 @@
return res;
}
+uint64_t float64_to_uint64 (float64 a STATUS_PARAM)
+{
+ int64_t v;
+
+ v = int64_to_float64(INT64_MIN STATUS_VAR);
+ v = float64_to_int64((a + v) STATUS_VAR);
+
+ return v - INT64_MIN;
+}
+
+uint64_t float64_to_uint64_round_to_zero (float64 a STATUS_PARAM)
+{
+ int64_t v;
+
+ v = int64_to_float64(INT64_MIN STATUS_VAR);
+ v = float64_to_int64_round_to_zero((a + 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 ) \
Modified: trunk/src/host/qemu-neo1973/fpu/softfloat.h
===================================================================
--- trunk/src/host/qemu-neo1973/fpu/softfloat.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/fpu/softfloat.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -32,6 +32,10 @@
#ifndef SOFTFLOAT_H
#define SOFTFLOAT_H
+#if defined(HOST_SOLARIS) && defined(NEEDS_LIBSUNMATH)
+#include <sunmath.h>
+#endif
+
#include <inttypes.h>
#include "config.h"
@@ -193,7 +197,9 @@
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
@@ -258,6 +264,8 @@
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 );
Modified: trunk/src/host/qemu-neo1973/gdbstub.c
===================================================================
--- trunk/src/host/qemu-neo1973/gdbstub.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/gdbstub.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -52,26 +52,30 @@
RS_GETLINE,
RS_CHKSUM1,
RS_CHKSUM2,
+ RS_SYSCALL,
};
-/* XXX: This is not thread safe. Do we care? */
-static int gdbserver_fd = -1;
-
typedef struct GDBState {
CPUState *env; /* current CPU */
enum RSState state; /* parsing state */
- int fd;
char line_buf[4096];
int line_buf_index;
int line_csum;
+ char last_packet[4100];
+ int last_packet_len;
#ifdef CONFIG_USER_ONLY
+ int fd;
int running_state;
+#else
+ CharDriverState *chr;
#endif
} GDBState;
#ifdef CONFIG_USER_ONLY
+/* XXX: This is not thread safe. Do we care? */
+static int gdbserver_fd = -1;
+
/* XXX: remove this hack. */
static GDBState gdbserver_state;
-#endif
static int get_char(GDBState *s)
{
@@ -91,9 +95,32 @@
}
return ch;
}
+#endif
+/* 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)
{
+#ifdef CONFIG_USER_ONLY
int ret;
while (len > 0) {
@@ -106,6 +133,9 @@
len -= ret;
}
}
+#else
+ qemu_chr_write(s->chr, buf, len);
+#endif
}
static inline int fromhex(int v)
@@ -154,33 +184,39 @@
/* return -1 if error, 0 if OK */
static int put_packet(GDBState *s, char *buf)
{
- char buf1[3];
- int len, csum, ch, i;
+ int len, csum, i;
+ char *p;
#ifdef DEBUG_GDB
printf("reply='%s'\n", buf);
#endif
for(;;) {
- buf1[0] = '$';
- put_buffer(s, buf1, 1);
+ p = s->last_packet;
+ *(p++) = '$';
len = strlen(buf);
- put_buffer(s, buf, len);
+ memcpy(p, buf, len);
+ p += len;
csum = 0;
for(i = 0; i < len; i++) {
csum += buf[i];
}
- buf1[0] = '#';
- buf1[1] = tohex((csum >> 4) & 0xf);
- buf1[2] = tohex((csum) & 0xf);
+ *(p++) = '#';
+ *(p++) = tohex((csum >> 4) & 0xf);
+ *(p++) = tohex((csum) & 0xf);
- put_buffer(s, buf1, 3);
+ s->last_packet_len = p - s->last_packet;
+ put_buffer(s, s->last_packet, s->last_packet_len);
- ch = get_char(s);
- if (ch < 0)
+#ifdef CONFIG_USER_ONLY
+ i = get_char(s);
+ if (i < 0)
return -1;
- if (ch == '+')
+ if (i == '+')
break;
+#else
+ break;
+#endif
}
return 0;
}
@@ -271,7 +307,7 @@
registers[98] = tswapl(tmp);
registers[99] = tswapl(env->lr);
registers[100] = tswapl(env->ctr);
- registers[101] = tswapl(do_load_xer(env));
+ registers[101] = tswapl(ppc_load_xer(env));
registers[102] = 0;
return 103 * 4;
@@ -299,7 +335,7 @@
env->crf[i] = (registers[98] >> (32 - ((i + 1) * 4))) & 0xF;
env->lr = tswapl(registers[99]);
env->ctr = tswapl(registers[100]);
- do_store_xer(env, tswapl(registers[101]));
+ ppc_store_xer(env, tswapl(registers[101]));
}
#elif defined (TARGET_SPARC)
static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
@@ -341,9 +377,9 @@
for (i = 0; i < 64; i += 2) {
uint64_t tmp;
- tmp = (uint64_t)tswap32(*((uint32_t *)&env->fpr[i])) << 32;
- tmp |= tswap32(*((uint32_t *)&env->fpr[i + 1]));
- registers[i/2 + 32] = tmp;
+ tmp = ((uint64_t)*(uint32_t *)&env->fpr[i]) << 32;
+ tmp |= *(uint32_t *)&env->fpr[i + 1];
+ registers[i / 2 + 32] = tswap64(tmp);
}
registers[64] = tswapl(env->pc);
registers[65] = tswapl(env->npc);
@@ -383,8 +419,11 @@
env->fsr = tswapl(registers[70]);
#else
for (i = 0; i < 64; i += 2) {
- *((uint32_t *)&env->fpr[i]) = tswap32(registers[i/2 + 32] >> 32);
- *((uint32_t *)&env->fpr[i + 1]) = tswap32(registers[i/2 + 32] & 0xffffffff);
+ uint64_t tmp;
+
+ tmp = tswap64(registers[i / 2 + 32]);
+ *((uint32_t *)&env->fpr[i]) = tmp >> 32;
+ *((uint32_t *)&env->fpr[i + 1]) = tmp & 0xffffffff;
}
env->pc = tswapl(registers[64]);
env->npc = tswapl(registers[65]);
@@ -532,20 +571,21 @@
*(uint32_t *)ptr = tswapl(env->PC);
ptr += 4;
-#ifdef MIPS_USES_FPU
- for (i = 0; i < 32; i++)
+ if (env->CP0_Config1 & (1 << CP0C1_FP))
{
- *(uint32_t *)ptr = tswapl(FPR_W (env, i));
+ for (i = 0; i < 32; i++)
+ {
+ *(uint32_t *)ptr = tswapl(env->fpr[i].fs[FP_ENDIAN_IDX]);
+ ptr += 4;
+ }
+
+ *(uint32_t *)ptr = tswapl(env->fcr31);
ptr += 4;
+
+ *(uint32_t *)ptr = tswapl(env->fcr0);
+ ptr += 4;
}
- *(uint32_t *)ptr = tswapl(env->fcr31);
- ptr += 4;
-
- *(uint32_t *)ptr = tswapl(env->fcr0);
- ptr += 4;
-#endif
-
/* 32 FP registers, fsr, fir, fp. Not yet implemented. */
/* what's 'fp' mean here? */
@@ -593,27 +633,28 @@
env->PC = tswapl(*(uint32_t *)ptr);
ptr += 4;
-#ifdef MIPS_USES_FPU
- for (i = 0; i < 32; i++)
+ if (env->CP0_Config1 & (1 << CP0C1_FP))
{
- FPR_W (env, i) = tswapl(*(uint32_t *)ptr);
+ for (i = 0; i < 32; i++)
+ {
+ env->fpr[i].fs[FP_ENDIAN_IDX] = tswapl(*(uint32_t *)ptr);
+ ptr += 4;
+ }
+
+ env->fcr31 = tswapl(*(uint32_t *)ptr) & 0x0183FFFF;
ptr += 4;
- }
- env->fcr31 = tswapl(*(uint32_t *)ptr) & 0x0183FFFF;
- ptr += 4;
+ env->fcr0 = tswapl(*(uint32_t *)ptr);
+ ptr += 4;
- env->fcr0 = tswapl(*(uint32_t *)ptr);
- ptr += 4;
+ /* set rounding mode */
+ RESTORE_ROUNDING_MODE;
- /* set rounding mode */
- RESTORE_ROUNDING_MODE;
-
#ifndef CONFIG_SOFTFLOAT
- /* no floating point exception for native float */
- SET_FP_ENABLE(env->fcr31, 0);
+ /* no floating point exception for native float */
+ SET_FP_ENABLE(env->fcr31, 0);
#endif
-#endif
+ }
}
#elif defined (TARGET_SH4)
static int cpu_gdb_read_registers(CPUState *env, uint8_t *mem_buf)
@@ -741,6 +782,34 @@
vm_start();
#endif
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 {
+#ifdef CONFIG_USER_ONLY
+ s->running_state = 1;
+#else
+ vm_start();
+#endif
+ }
+ }
+ break;
case 'g':
reg_size = cpu_gdb_read_registers(env, mem_buf);
memtohex(buf, mem_buf, reg_size);
@@ -790,6 +859,12 @@
if (cpu_breakpoint_insert(env, addr) < 0)
goto breakpoint_error;
put_packet(s, "OK");
+#ifndef CONFIG_USER_ONLY
+ } else if (type == 2) {
+ if (cpu_watchpoint_insert(env, addr) < 0)
+ goto breakpoint_error;
+ put_packet(s, "OK");
+#endif
} else {
breakpoint_error:
put_packet(s, "E22");
@@ -806,11 +881,16 @@
if (type == 0 || type == 1) {
cpu_breakpoint_remove(env, addr);
put_packet(s, "OK");
+#ifndef CONFIG_USER_ONLY
+ } else if (type == 2) {
+ cpu_watchpoint_remove(env, addr);
+ put_packet(s, "OK");
+#endif
} else {
goto breakpoint_error;
}
break;
-#ifdef CONFIG_USER_ONLY
+#ifdef CONFIG_LINUX_USER
case 'q':
if (strncmp(p, "Offsets", 7) == 0) {
TaskState *ts = env->opaque;
@@ -841,10 +921,21 @@
char buf[256];
int ret;
+ if (s->state == RS_SYSCALL)
+ return;
+
/* disable single step if it was enable */
cpu_single_step(s->env, 0);
if (reason == EXCP_DEBUG) {
+ if (s->env->watchpoint_hit) {
+ snprintf(buf, sizeof(buf), "T%02xwatch:" TARGET_FMT_lx ";",
+ SIGTRAP,
+ s->env->watchpoint[s->env->watchpoint_hit - 1].vaddr);
+ put_packet(s, buf);
+ s->env->watchpoint_hit = 0;
+ return;
+ }
tb_flush(s->env);
ret = SIGTRAP;
} else if (reason == EXCP_INTERRUPT) {
@@ -857,6 +948,60 @@
}
#endif
+/* 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_SYSCALL;
+#ifndef CONFIG_USER_ONLY
+ vm_stop(EXCP_DEBUG);
+#endif
+ 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 CONFIG_USER_ONLY
+ gdb_handlesig(s->env, 0);
+#else
+ cpu_interrupt(s->env, CPU_INTERRUPT_EXIT);
+#endif
+}
+
static void gdb_read_byte(GDBState *s, int ch)
{
CPUState *env = s->env;
@@ -864,6 +1009,26 @@
char reply[1];
#ifndef CONFIG_USER_ONLY
+ if (s->last_packet_len) {
+ /* Waiting for a response to the last packet. If we see the start
+ of a new command then abandon the previous response. */
+ if (ch == '-') {
+#ifdef DEBUG_GDB
+ printf("Got NACK, retransmitting\n");
+#endif
+ put_buffer(s, s->last_packet, s->last_packet_len);
+ }
+#ifdef DEBUG_GDB
+ else if (ch == '+')
+ printf("Got ACK\n");
+ else
+ printf("Got '%c' when expecting ACK/NACK\n", ch);
+#endif
+ if (ch == '+' || ch == '$')
+ s->last_packet_len = 0;
+ if (ch != '$')
+ return;
+ }
if (vm_running) {
/* when the CPU is running, we cannot do anything except stop
it when receiving a char */
@@ -908,6 +1073,8 @@
s->state = gdb_handle_packet(s, env, s->line_buf);
}
break;
+ default:
+ abort();
}
}
}
@@ -972,30 +1139,7 @@
put_packet(s, buf);
}
-#else
-static void gdb_read(void *opaque)
-{
- GDBState *s = opaque;
- int i, size;
- uint8_t buf[4096];
- size = recv(s->fd, buf, sizeof(buf), 0);
- if (size < 0)
- return;
- if (size == 0) {
- /* end of connection */
- qemu_del_vm_stop_handler(gdb_vm_stopped, s);
- qemu_set_fd_handler(s->fd, NULL, NULL, NULL);
- qemu_free(s);
- vm_start();
- } else {
- for(i = 0; i < size; i++)
- gdb_read_byte(s, buf[i]);
- }
-}
-
-#endif
-
static void gdb_accept(void *opaque)
{
GDBState *s;
@@ -1018,32 +1162,14 @@
val = 1;
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
-#ifdef CONFIG_USER_ONLY
s = &gdbserver_state;
memset (s, 0, sizeof (GDBState));
-#else
- s = qemu_mallocz(sizeof(GDBState));
- if (!s) {
- close(fd);
- return;
- }
-#endif
s->env = first_cpu; /* XXX: allow to change CPU */
s->fd = fd;
-#ifdef CONFIG_USER_ONLY
+ gdb_syscall_state = s;
+
fcntl(fd, F_SETFL, O_NONBLOCK);
-#else
- socket_set_nonblock(fd);
-
- /* stop the VM */
- vm_stop(EXCP_INTERRUPT);
-
- /* start handling I/O */
- qemu_set_fd_handler(s->fd, gdb_read, NULL, s);
- /* when the VM is stopped, the following callback is called */
- qemu_add_vm_stop_handler(gdb_vm_stopped, s);
-#endif
}
static int gdbserver_open(int port)
@@ -1074,9 +1200,6 @@
perror("listen");
return -1;
}
-#ifndef CONFIG_USER_ONLY
- socket_set_nonblock(fd);
-#endif
return fd;
}
@@ -1086,10 +1209,69 @@
if (gdbserver_fd < 0)
return -1;
/* accept connections */
-#ifdef CONFIG_USER_ONLY
gdb_accept (NULL);
+ return 0;
+}
#else
- qemu_set_fd_handler(gdbserver_fd, gdb_accept, NULL, NULL);
-#endif
+static int gdb_chr_can_recieve(void *opaque)
+{
+ return 1;
+}
+
+static void gdb_chr_recieve(void *opaque, const uint8_t *buf, int size)
+{
+ GDBState *s = opaque;
+ int i;
+
+ for (i = 0; i < size; i++) {
+ gdb_read_byte(s, buf[i]);
+ }
+}
+
+static void gdb_chr_event(void *opaque, int event)
+{
+ switch (event) {
+ case CHR_EVENT_RESET:
+ vm_stop(EXCP_INTERRUPT);
+ gdb_syscall_state = opaque;
+ break;
+ default:
+ break;
+ }
+}
+
+int gdbserver_start(const char *port)
+{
+ GDBState *s;
+ char gdbstub_port_name[128];
+ int port_num;
+ char *p;
+ CharDriverState *chr;
+
+ if (!port || !*port)
+ return -1;
+
+ port_num = strtol(port, &p, 10);
+ if (*p == 0) {
+ /* A numeric value is interpreted as a port number. */
+ snprintf(gdbstub_port_name, sizeof(gdbstub_port_name),
+ "tcp::%d,nowait,nodelay,server", port_num);
+ port = gdbstub_port_name;
+ }
+
+ chr = qemu_chr_open(port);
+ if (!chr)
+ return -1;
+
+ s = qemu_mallocz(sizeof(GDBState));
+ if (!s) {
+ return -1;
+ }
+ s->env = first_cpu; /* XXX: allow to change CPU */
+ s->chr = chr;
+ qemu_chr_add_handlers(chr, gdb_chr_can_recieve, gdb_chr_recieve,
+ gdb_chr_event, s);
+ qemu_add_vm_stop_handler(gdb_vm_stopped, s);
return 0;
}
+#endif
Modified: trunk/src/host/qemu-neo1973/gdbstub.h
===================================================================
--- trunk/src/host/qemu-neo1973/gdbstub.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/gdbstub.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -1,12 +1,19 @@
#ifndef GDBSTUB_H
#define GDBSTUB_H
-#define DEFAULT_GDBSTUB_PORT 1234
+#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);
#ifdef CONFIG_USER_ONLY
int gdb_handlesig (CPUState *, int);
void gdb_exit(CPUState *, int);
+int gdbserver_start(int);
+#else
+int gdbserver_start(const char *port);
#endif
-int gdbserver_start(int);
#endif
Added: trunk/src/host/qemu-neo1973/hostregs_helper.h
===================================================================
--- trunk/src/host/qemu-neo1973/hostregs_helper.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hostregs_helper.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,98 @@
+/*
+ * Save/restore host registrs.
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* The GCC global register vairable extension is used to reserve some
+ host registers for use by dyngen. 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
+
+#ifdef AREG3
+DO_REG(3)
+#endif
+
+#ifdef AREG4
+DO_REG(4)
+#endif
+
+#ifdef AREG5
+DO_REG(5)
+#endif
+
+#ifdef AREG6
+DO_REG(6)
+#endif
+
+#ifdef AREG7
+DO_REG(7)
+#endif
+
+#ifdef AREG8
+DO_REG(8)
+#endif
+
+#ifdef AREG9
+DO_REG(9)
+#endif
+
+#ifdef AREG10
+DO_REG(10)
+#endif
+
+#ifdef AREG11
+DO_REG(11)
+#endif
+
+#undef SAVE_HOST_REGS
+#undef DECLARE_HOST_REGS
+#undef DO_REG
Modified: trunk/src/host/qemu-neo1973/hw/acpi.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/acpi.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/acpi.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -24,6 +24,7 @@
#define PM_FREQ 3579545
#define ACPI_DBG_IO_ADDR 0xb044
+#define SMB_IO_BASE 0xb100
typedef struct PIIX4PMState {
PCIDevice dev;
@@ -34,6 +35,15 @@
uint8_t apms;
QEMUTimer *tmr_timer;
int64_t tmr_overflow_time;
+ i2c_bus *smbus;
+ uint8_t smb_stat;
+ uint8_t smb_ctl;
+ uint8_t smb_cmd;
+ uint8_t smb_addr;
+ uint8_t smb_data0;
+ uint8_t smb_data1;
+ uint8_t smb_data[32];
+ uint8_t smb_index;
} PIIX4PMState;
#define RTC_EN (1 << 10)
@@ -45,6 +55,14 @@
#define SUS_EN (1 << 13)
+#define SMBHSTSTS 0x00
+#define SMBHSTCNT 0x02
+#define SMBHSTCMD 0x03
+#define SMBHSTADD 0x04
+#define SMBHSTDAT0 0x05
+#define SMBHSTDAT1 0x06
+#define SMBBLKDAT 0x07
+
static uint32_t get_pmtmr(PIIX4PMState *s)
{
uint32_t d;
@@ -71,7 +89,7 @@
pmsts = get_pmsts(s);
sci_level = (((pmsts & s->pmen) &
(RTC_EN | PWRBTN_EN | GBL_EN | TMROF_EN)) != 0);
- pci_set_irq(&s->dev, 0, sci_level);
+ qemu_set_irq(s->dev.irq[0], sci_level);
/* schedule a timer interruption if needed */
if ((s->pmen & TMROF_EN) && !(pmsts & TMROF_EN)) {
expire_time = muldiv64(s->tmr_overflow_time, ticks_per_sec, PM_FREQ);
@@ -231,6 +249,141 @@
#endif
}
+static void smb_transaction(PIIX4PMState *s)
+{
+ uint8_t prot = (s->smb_ctl >> 2) & 0x07;
+ uint8_t read = s->smb_addr & 0x01;
+ uint8_t cmd = s->smb_cmd;
+ uint8_t addr = s->smb_addr >> 1;
+ i2c_bus *bus = s->smbus;
+
+#ifdef DEBUG
+ printf("SMBus trans addr=0x%02x prot=0x%02x\n", addr, prot);
+#endif
+ switch(prot) {
+ case 0x0:
+ smbus_quick_command(bus, addr, read);
+ break;
+ case 0x1:
+ if (read) {
+ s->smb_data0 = smbus_receive_byte(bus, addr);
+ } else {
+ smbus_send_byte(bus, addr, cmd);
+ }
+ break;
+ case 0x2:
+ if (read) {
+ s->smb_data0 = smbus_read_byte(bus, addr, cmd);
+ } else {
+ smbus_write_byte(bus, addr, cmd, s->smb_data0);
+ }
+ break;
+ case 0x3:
+ if (read) {
+ uint16_t val;
+ smbus_read_word(bus, addr, cmd);
+ s->smb_data0 = val;
+ s->smb_data1 = val >> 8;
+ } else {
+ smbus_write_word(bus, addr, cmd, (s->smb_data1 << 8) | s->smb_data0);
+ }
+ break;
+ case 0x5:
+ if (read) {
+ s->smb_data0 = smbus_read_block(bus, addr, cmd, s->smb_data);
+ } else {
+ smbus_write_block(bus, addr, cmd, s->smb_data, s->smb_data0);
+ }
+ break;
+ default:
+ goto error;
+ }
+ return;
+
+ error:
+ s->smb_stat |= 0x04;
+}
+
+static void smb_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
+{
+ PIIX4PMState *s = opaque;
+ addr &= 0x3f;
+#ifdef DEBUG
+ printf("SMB writeb port=0x%04x val=0x%02x\n", addr, val);
+#endif
+ switch(addr) {
+ case SMBHSTSTS:
+ s->smb_stat = 0;
+ s->smb_index = 0;
+ break;
+ case SMBHSTCNT:
+ s->smb_ctl = val;
+ if (val & 0x40)
+ smb_transaction(s);
+ break;
+ case SMBHSTCMD:
+ s->smb_cmd = val;
+ break;
+ case SMBHSTADD:
+ s->smb_addr = val;
+ break;
+ case SMBHSTDAT0:
+ s->smb_data0 = val;
+ break;
+ case SMBHSTDAT1:
+ s->smb_data1 = val;
+ break;
+ case SMBBLKDAT:
+ s->smb_data[s->smb_index++] = val;
+ if (s->smb_index > 31)
+ s->smb_index = 0;
+ break;
+ default:
+ break;
+ }
+}
+
+static uint32_t smb_ioport_readb(void *opaque, uint32_t addr)
+{
+ PIIX4PMState *s = opaque;
+ uint32_t val;
+
+ addr &= 0x3f;
+ switch(addr) {
+ case SMBHSTSTS:
+ val = s->smb_stat;
+ break;
+ case SMBHSTCNT:
+ s->smb_index = 0;
+ val = s->smb_ctl & 0x1f;
+ break;
+ case SMBHSTCMD:
+ val = s->smb_cmd;
+ break;
+ case SMBHSTADD:
+ val = s->smb_addr;
+ break;
+ case SMBHSTDAT0:
+ val = s->smb_data0;
+ break;
+ case SMBHSTDAT1:
+ val = s->smb_data1;
+ break;
+ case SMBBLKDAT:
+ val = s->smb_data[s->smb_index++];
+ if (s->smb_index > 31)
+ s->smb_index = 0;
+ break;
+ default:
+ val = 0;
+ break;
+ }
+#ifdef DEBUG
+ printf("SMB readb port=0x%04x val=0x%02x\n", addr, val);
+#endif
+ return val;
+}
+
static void pm_io_space_update(PIIX4PMState *s)
{
uint32_t pm_io_base;
@@ -298,10 +451,11 @@
return 0;
}
-void piix4_pm_init(PCIBus *bus, int devfn)
+i2c_bus *piix4_pm_init(PCIBus *bus, int devfn)
{
PIIX4PMState *s;
uint8_t *pci_conf;
+ uint32_t smb_io_base;
s = (PIIX4PMState *)pci_register_device(bus,
"PM", sizeof(PIIX4PMState),
@@ -332,7 +486,17 @@
pci_conf[0x67] = (serial_hds[0] != NULL ? 0x08 : 0) |
(serial_hds[1] != NULL ? 0x90 : 0);
+ smb_io_base = SMB_IO_BASE;
+ pci_conf[0x90] = smb_io_base | 1;
+ pci_conf[0x91] = smb_io_base >> 8;
+ pci_conf[0xd2] = 0x09;
+ register_ioport_write(smb_io_base, 64, 1, smb_ioport_writeb, s);
+ register_ioport_read(smb_io_base, 64, 1, smb_ioport_readb, s);
+
s->tmr_timer = qemu_new_timer(vm_clock, pm_tmr_timer, s);
register_savevm("piix4_pm", 0, 1, pm_save, pm_load, s);
+
+ s->smbus = i2c_init_bus();
+ return s->smbus;
}
Modified: trunk/src/host/qemu-neo1973/hw/adlib.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/adlib.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/adlib.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -267,7 +267,7 @@
AUD_remove_card (&s->card);
}
-int Adlib_init (AudioState *audio)
+int Adlib_init (AudioState *audio, qemu_irq *pic)
{
AdlibState *s = &glob_adlib;
audsettings_t as;
Modified: trunk/src/host/qemu-neo1973/hw/ads7846.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/ads7846.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/ads7846.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -4,14 +4,13 @@
* Copyright (c) 2006 Openedhand Ltd.
* Written by Andrzej Zaborowski <balrog at zabor.org>
*
- * This code is licensed under the GPLv2.
+ * This code is licensed under the GNU GPL v2.
*/
#include <vl.h>
struct ads7846_state_s {
- void (*interrupt)(void *opaque, int level);
- void *opaque;
+ qemu_irq interrupt;
int input[8];
int pressure;
@@ -48,7 +47,7 @@
static void ads7846_int_update(struct ads7846_state_s *s)
{
if (s->interrupt)
- s->interrupt(s->opaque, s->pressure == 0);
+ qemu_set_irq(s->interrupt, s->pressure == 0);
}
uint32_t ads7846_read(void *opaque)
@@ -101,13 +100,15 @@
s->input[4] = ADS_Z2POS(x, y);
s->input[5] = ADS_XPOS(x, y);
}
- s->pressure = !!buttons_state;
- ads7846_int_update(s);
+ if (s->pressure == !buttons_state) {
+ s->pressure = !!buttons_state;
+
+ ads7846_int_update(s);
+ }
}
-struct ads7846_state_s *ads7846_init(
- void (*penirq)(void *opaque, int level), void *opaque)
+struct ads7846_state_s *ads7846_init(qemu_irq penirq)
{
struct ads7846_state_s *s;
s = (struct ads7846_state_s *)
@@ -115,7 +116,6 @@
memset(s, 0, sizeof(struct ads7846_state_s));
s->interrupt = penirq;
- s->opaque = opaque;
s->input[0] = ADS_TEMP0; /* TEMP0 */
s->input[2] = ADS_VBAT; /* VBAT */
Added: trunk/src/host/qemu-neo1973/hw/alpha_palcode.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/alpha_palcode.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/alpha_palcode.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,1099 @@
+/*
+ * Alpha emulation - PALcode emulation for qemu.
+ *
+ * Copyright (c) 2007 Jocelyn Mayer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "qemu.h"
+#include "cpu.h"
+#include "exec-all.h"
+
+#if !defined (CONFIG_USER_ONLY)
+/* Shared handlers */
+static void pal_reset (CPUState *env);
+/* Console handlers */
+static void pal_console_call (CPUState *env, uint32_t palcode);
+/* OpenVMS handlers */
+static void pal_openvms_call (CPUState *env, uint32_t palcode);
+/* UNIX / Linux handlers */
+static void pal_unix_call (CPUState *env, uint32_t palcode);
+
+pal_handler_t pal_handlers[] = {
+ /* Console handler */
+ {
+ .reset = &pal_reset,
+ .call_pal = &pal_console_call,
+ },
+ /* OpenVMS handler */
+ {
+ .reset = &pal_reset,
+ .call_pal = &pal_openvms_call,
+ },
+ /* UNIX / Linux handler */
+ {
+ .reset = &pal_reset,
+ .call_pal = &pal_unix_call,
+ },
+};
+
+#if 0
+/* One must explicitely check that the TB is valid and the FOE bit is reset */
+static void update_itb ()
+{
+ /* This writes into a temp register, not the actual one */
+ mtpr(TB_TAG);
+ mtpr(TB_CTL);
+ /* This commits the TB update */
+ mtpr(ITB_PTE);
+}
+
+static void update_dtb ();
+{
+ mtpr(TB_CTL);
+ /* This write into a temp register, not the actual one */
+ mtpr(TB_TAG);
+ /* This commits the TB update */
+ mtpr(DTB_PTE);
+}
+#endif
+
+static void pal_reset (CPUState *env)
+{
+}
+
+static void do_swappal (CPUState *env, uint64_t palid)
+{
+ pal_handler_t *pal_handler;
+ int status;
+
+ status = 0;
+ switch (palid) {
+ case 0 ... 2:
+ pal_handler = &pal_handlers[palid];
+ env->pal_handler = pal_handler;
+ env->ipr[IPR_PAL_BASE] = -1ULL;
+ (*pal_handler->reset)(env);
+ break;
+ case 3 ... 255:
+ /* Unknown identifier */
+ env->ir[0] = 1;
+ return;
+ default:
+ /* We were given the entry point address */
+ env->pal_handler = NULL;
+ env->ipr[IPR_PAL_BASE] = palid;
+ env->pc = env->ipr[IPR_PAL_BASE];
+ cpu_loop_exit();
+ }
+}
+
+static void pal_console_call (CPUState *env, uint32_t palcode)
+{
+ uint64_t palid;
+
+ if (palcode < 0x00000080) {
+ /* Privileged palcodes */
+ if (!(env->ps >> 3)) {
+ /* TODO: generate privilege exception */
+ }
+ }
+ switch (palcode) {
+ case 0x00000000:
+ /* HALT */
+ /* REQUIRED */
+ break;
+ case 0x00000001:
+ /* CFLUSH */
+ break;
+ case 0x00000002:
+ /* DRAINA */
+ /* REQUIRED */
+ /* Implemented as no-op */
+ break;
+ case 0x00000009:
+ /* CSERVE */
+ /* REQUIRED */
+ break;
+ case 0x0000000A:
+ /* SWPPAL */
+ /* REQUIRED */
+ palid = env->ir[16];
+ do_swappal(env, palid);
+ break;
+ case 0x00000080:
+ /* BPT */
+ /* REQUIRED */
+ break;
+ case 0x00000081:
+ /* BUGCHK */
+ /* REQUIRED */
+ break;
+ case 0x00000086:
+ /* IMB */
+ /* REQUIRED */
+ /* Implemented as no-op */
+ break;
+ case 0x0000009E:
+ /* RDUNIQUE */
+ /* REQUIRED */
+ break;
+ case 0x0000009F:
+ /* WRUNIQUE */
+ /* REQUIRED */
+ break;
+ case 0x000000AA:
+ /* GENTRAP */
+ /* REQUIRED */
+ break;
+ default:
+ break;
+ }
+}
+
+static void pal_openvms_call (CPUState *env, uint32_t palcode)
+{
+ uint64_t palid, val, oldval;
+
+ if (palcode < 0x00000080) {
+ /* Privileged palcodes */
+ if (!(env->ps >> 3)) {
+ /* TODO: generate privilege exception */
+ }
+ }
+ switch (palcode) {
+ case 0x00000000:
+ /* HALT */
+ /* REQUIRED */
+ break;
+ case 0x00000001:
+ /* CFLUSH */
+ break;
+ case 0x00000002:
+ /* DRAINA */
+ /* REQUIRED */
+ /* Implemented as no-op */
+ break;
+ case 0x00000003:
+ /* LDQP */
+ break;
+ case 0x00000004:
+ /* STQP */
+ break;
+ case 0x00000005:
+ /* SWPCTX */
+ break;
+ case 0x00000006:
+ /* MFPR_ASN */
+ if (cpu_alpha_mfpr(env, IPR_ASN, &val) == 0)
+ env->ir[0] = val;
+ break;
+ case 0x00000007:
+ /* MTPR_ASTEN */
+ val = env->ir[16];
+ if (cpu_alpha_mtpr(env, IPR_ASTEN, val, &oldval) == 1)
+ env->ir[0] = val;
+ break;
+ case 0x00000008:
+ /* MTPR_ASTSR */
+ val = env->ir[16];
+ if (cpu_alpha_mtpr(env, IPR_ASTSR, val, &oldval) == 1)
+ env->ir[0] = val;
+ break;
+ case 0x00000009:
+ /* CSERVE */
+ /* REQUIRED */
+ break;
+ case 0x0000000A:
+ /* SWPPAL */
+ /* REQUIRED */
+ palid = env->ir[16];
+ do_swappal(env, palid);
+ break;
+ case 0x0000000B:
+ /* MFPR_FEN */
+ if (cpu_alpha_mfpr(env, IPR_FEN, &val) == 0)
+ env->ir[0] = val;
+ break;
+ case 0x0000000C:
+ /* MTPR_FEN */
+ val = env->ir[16];
+ if (cpu_alpha_mtpr(env, IPR_FEN, val, &oldval) == 1)
+ env->ir[0] = val;
+ break;
+ case 0x0000000D:
+ /* MTPR_IPIR */
+ val = env->ir[16];
+ if (cpu_alpha_mtpr(env, IPR_IPIR, val, &oldval) == 1)
+ env->ir[0] = val;
+ break;
+ case 0x0000000E:
+ /* MFPR_IPL */
+ if (cpu_alpha_mfpr(env, IPR_IPL, &val) == 0)
+ env->ir[0] = val;
+ break;
+ case 0x0000000F:
+ /* MTPR_IPL */
+ val = env->ir[16];
+ if (cpu_alpha_mtpr(env, IPR_IPL, val, &oldval) == 1)
+ env->ir[0] = val;
+ break;
+ case 0x00000010:
+ /* MFPR_MCES */
+ if (cpu_alpha_mfpr(env, IPR_MCES, &val) == 0)
+ env->ir[0] = val;
+ break;
+ case 0x00000011:
+ /* MTPR_MCES */
+ val = env->ir[16];
+ if (cpu_alpha_mtpr(env, IPR_MCES, val, &oldval) == 1)
+ env->ir[0] = val;
+ break;
+ case 0x00000012:
+ /* MFPR_PCBB */
+ if (cpu_alpha_mfpr(env, IPR_PCBB, &val) == 0)
+ env->ir[0] = val;
+ break;
+ case 0x00000013:
+ /* MFPR_PRBR */
+ if (cpu_alpha_mfpr(env, IPR_PRBR, &val) == 0)
+ env->ir[0] = val;
+ break;
+ case 0x00000014:
+ /* MTPR_PRBR */
+ val = env->ir[16];
+ if (cpu_alpha_mtpr(env, IPR_PRBR, val, &oldval) == 1)
+ env->ir[0] = val;
+ break;
+ case 0x00000015:
+ /* MFPR_PTBR */
+ if (cpu_alpha_mfpr(env, IPR_PTBR, &val) == 0)
+ env->ir[0] = val;
+ break;
+ case 0x00000016:
+ /* MFPR_SCBB */
+ if (cpu_alpha_mfpr(env, IPR_SCBB, &val) == 0)
+ env->ir[0] = val;
+ break;
+ case 0x00000017:
+ /* MTPR_SCBB */
+ val = env->ir[16];
+ if (cpu_alpha_mtpr(env, IPR_SCBB, val, &oldval) == 1)
+ env->ir[0] = val;
+ break;
+ case 0x00000018:
+ /* MTPR_SIRR */
+ val = env->ir[16];
+ if (cpu_alpha_mtpr(env, IPR_SIRR, val, &oldval) == 1)
+ env->ir[0] = val;
+ break;
+ case 0x00000019:
+ /* MFPR_SISR */
+ if (cpu_alpha_mfpr(env, IPR_SISR, &val) == 0)
+ env->ir[0] = val;
+ break;
+ case 0x0000001A:
+ /* MFPR_TBCHK */
+ if (cpu_alpha_mfpr(env, IPR_TBCHK, &val) == 0)
+ env->ir[0] = val;
+ break;
+ case 0x0000001B:
+ /* MTPR_TBIA */
+ val = env->ir[16];
+ if (cpu_alpha_mtpr(env, IPR_TBIA, val, &oldval) == 1)
+ env->ir[0] = val;
+ break;
+ case 0x0000001C:
+ /* MTPR_TBIAP */
+ val = env->ir[16];
+ if (cpu_alpha_mtpr(env, IPR_TBIAP, val, &oldval) == 1)
+ env->ir[0] = val;
+ break;
+ case 0x0000001D:
+ /* MTPR_TBIS */
+ val = env->ir[16];
+ if (cpu_alpha_mtpr(env, IPR_TBIS, val, &oldval) == 1)
+ env->ir[0] = val;
+ break;
+ case 0x0000001E:
+ /* MFPR_ESP */
+ if (cpu_alpha_mfpr(env, IPR_ESP, &val) == 0)
+ env->ir[0] = val;
+ break;
+ case 0x0000001F:
+ /* MTPR_ESP */
+ val = env->ir[16];
+ if (cpu_alpha_mtpr(env, IPR_ESP, val, &oldval) == 1)
+ env->ir[0] = val;
+ break;
+ case 0x00000020:
+ /* MFPR_SSP */
+ if (cpu_alpha_mfpr(env, IPR_SSP, &val) == 0)
+ env->ir[0] = val;
+ break;
+ case 0x00000021:
+ /* MTPR_SSP */
+ val = env->ir[16];
+ if (cpu_alpha_mtpr(env, IPR_SSP, val, &oldval) == 1)
+ env->ir[0] = val;
+ break;
+ case 0x00000022:
+ /* MFPR_USP */
+ if (cpu_alpha_mfpr(env, IPR_USP, &val) == 0)
+ env->ir[0] = val;
+ break;
+ case 0x00000023:
+ /* MTPR_USP */
+ val = env->ir[16];
+ if (cpu_alpha_mtpr(env, IPR_USP, val, &oldval) == 1)
+ env->ir[0] = val;
+ break;
+ case 0x00000024:
+ /* MTPR_TBISD */
+ val = env->ir[16];
+ if (cpu_alpha_mtpr(env, IPR_TBISD, val, &oldval) == 1)
+ env->ir[0] = val;
+ break;
+ case 0x00000025:
+ /* MTPR_TBISI */
+ val = env->ir[16];
+ if (cpu_alpha_mtpr(env, IPR_TBISI, val, &oldval) == 1)
+ env->ir[0] = val;
+ break;
+ case 0x00000026:
+ /* MFPR_ASTEN */
+ if (cpu_alpha_mfpr(env, IPR_ASTEN, &val) == 0)
+ env->ir[0] = val;
+ break;
+ case 0x00000027:
+ /* MFPR_ASTSR */
+ if (cpu_alpha_mfpr(env, IPR_ASTSR, &val) == 0)
+ env->ir[0] = val;
+ break;
+ case 0x00000029:
+ /* MFPR_VPTB */
+ if (cpu_alpha_mfpr(env, IPR_VPTB, &val) == 0)
+ env->ir[0] = val;
+ break;
+ case 0x0000002A:
+ /* MTPR_VPTB */
+ val = env->ir[16];
+ if (cpu_alpha_mtpr(env, IPR_VPTB, val, &oldval) == 1)
+ env->ir[0] = val;
+ break;
+ case 0x0000002B:
+ /* MTPR_PERFMON */
+ val = env->ir[16];
+ if (cpu_alpha_mtpr(env, IPR_PERFMON, val, &oldval) == 1)
+ env->ir[0] = val;
+ break;
+ case 0x0000002E:
+ /* MTPR_DATFX */
+ val = env->ir[16];
+ if (cpu_alpha_mtpr(env, IPR_DATFX, val, &oldval) == 1)
+ env->ir[0] = val;
+ break;
+ case 0x0000003E:
+ /* WTINT */
+ break;
+ case 0x0000003F:
+ /* MFPR_WHAMI */
+ if (cpu_alpha_mfpr(env, IPR_WHAMI, &val) == 0)
+ env->ir[0] = val;
+ break;
+ case 0x00000080:
+ /* BPT */
+ /* REQUIRED */
+ break;
+ case 0x00000081:
+ /* BUGCHK */
+ /* REQUIRED */
+ break;
+ case 0x00000082:
+ /* CHME */
+ break;
+ case 0x00000083:
+ /* CHMK */
+ break;
+ case 0x00000084:
+ /* CHMS */
+ break;
+ case 0x00000085:
+ /* CHMU */
+ break;
+ case 0x00000086:
+ /* IMB */
+ /* REQUIRED */
+ /* Implemented as no-op */
+ break;
+ case 0x00000087:
+ /* INSQHIL */
+ break;
+ case 0x00000088:
+ /* INSQTIL */
+ break;
+ case 0x00000089:
+ /* INSQHIQ */
+ break;
+ case 0x0000008A:
+ /* INSQTIQ */
+ break;
+ case 0x0000008B:
+ /* INSQUEL */
+ break;
+ case 0x0000008C:
+ /* INSQUEQ */
+ break;
+ case 0x0000008D:
+ /* INSQUEL/D */
+ break;
+ case 0x0000008E:
+ /* INSQUEQ/D */
+ break;
+ case 0x0000008F:
+ /* PROBER */
+ break;
+ case 0x00000090:
+ /* PROBEW */
+ break;
+ case 0x00000091:
+ /* RD_PS */
+ break;
+ case 0x00000092:
+ /* REI */
+ break;
+ case 0x00000093:
+ /* REMQHIL */
+ break;
+ case 0x00000094:
+ /* REMQTIL */
+ break;
+ case 0x00000095:
+ /* REMQHIQ */
+ break;
+ case 0x00000096:
+ /* REMQTIQ */
+ break;
+ case 0x00000097:
+ /* REMQUEL */
+ break;
+ case 0x00000098:
+ /* REMQUEQ */
+ break;
+ case 0x00000099:
+ /* REMQUEL/D */
+ break;
+ case 0x0000009A:
+ /* REMQUEQ/D */
+ break;
+ case 0x0000009B:
+ /* SWASTEN */
+ break;
+ case 0x0000009C:
+ /* WR_PS_SW */
+ break;
+ case 0x0000009D:
+ /* RSCC */
+ break;
+ case 0x0000009E:
+ /* READ_UNQ */
+ /* REQUIRED */
+ break;
+ case 0x0000009F:
+ /* WRITE_UNQ */
+ /* REQUIRED */
+ break;
+ case 0x000000A0:
+ /* AMOVRR */
+ break;
+ case 0x000000A1:
+ /* AMOVRM */
+ break;
+ case 0x000000A2:
+ /* INSQHILR */
+ break;
+ case 0x000000A3:
+ /* INSQTILR */
+ break;
+ case 0x000000A4:
+ /* INSQHIQR */
+ break;
+ case 0x000000A5:
+ /* INSQTIQR */
+ break;
+ case 0x000000A6:
+ /* REMQHILR */
+ break;
+ case 0x000000A7:
+ /* REMQTILR */
+ break;
+ case 0x000000A8:
+ /* REMQHIQR */
+ break;
+ case 0x000000A9:
+ /* REMQTIQR */
+ break;
+ case 0x000000AA:
+ /* GENTRAP */
+ /* REQUIRED */
+ break;
+ case 0x000000AE:
+ /* CLRFEN */
+ break;
+ default:
+ break;
+ }
+}
+
+static void pal_unix_call (CPUState *env, uint32_t palcode)
+{
+ uint64_t palid, val, oldval;
+
+ if (palcode < 0x00000080) {
+ /* Privileged palcodes */
+ if (!(env->ps >> 3)) {
+ /* TODO: generate privilege exception */
+ }
+ }
+ switch (palcode) {
+ case 0x00000000:
+ /* HALT */
+ /* REQUIRED */
+ break;
+ case 0x00000001:
+ /* CFLUSH */
+ break;
+ case 0x00000002:
+ /* DRAINA */
+ /* REQUIRED */
+ /* Implemented as no-op */
+ break;
+ case 0x00000009:
+ /* CSERVE */
+ /* REQUIRED */
+ break;
+ case 0x0000000A:
+ /* SWPPAL */
+ /* REQUIRED */
+ palid = env->ir[16];
+ do_swappal(env, palid);
+ break;
+ case 0x0000000D:
+ /* WRIPIR */
+ val = env->ir[16];
+ if (cpu_alpha_mtpr(env, IPR_IPIR, val, &oldval) == 1)
+ env->ir[0] = val;
+ break;
+ case 0x00000010:
+ /* RDMCES */
+ if (cpu_alpha_mfpr(env, IPR_MCES, &val) == 0)
+ env->ir[0] = val;
+ break;
+ case 0x00000011:
+ /* WRMCES */
+ val = env->ir[16];
+ if (cpu_alpha_mtpr(env, IPR_MCES, val, &oldval) == 1)
+ env->ir[0] = val;
+ break;
+ case 0x0000002B:
+ /* WRFEN */
+ val = env->ir[16];
+ if (cpu_alpha_mtpr(env, IPR_PERFMON, val, &oldval) == 1)
+ env->ir[0] = val;
+ break;
+ case 0x0000002D:
+ /* WRVPTPTR */
+ break;
+ case 0x00000030:
+ /* SWPCTX */
+ break;
+ case 0x00000031:
+ /* WRVAL */
+ break;
+ case 0x00000032:
+ /* RDVAL */
+ break;
+ case 0x00000033:
+ /* TBI */
+ val = env->ir[16];
+ if (cpu_alpha_mtpr(env, IPR_TBIS, val, &oldval) == 1)
+ env->ir[0] = val;
+ break;
+ case 0x00000034:
+ /* WRENT */
+ break;
+ case 0x00000035:
+ /* SWPIPL */
+ break;
+ case 0x00000036:
+ /* RDPS */
+ break;
+ case 0x00000037:
+ /* WRKGP */
+ break;
+ case 0x00000038:
+ /* WRUSP */
+ val = env->ir[16];
+ if (cpu_alpha_mtpr(env, IPR_USP, val, &oldval) == 1)
+ env->ir[0] = val;
+ break;
+ case 0x00000039:
+ /* WRPERFMON */
+ val = env->ir[16];
+ if (cpu_alpha_mtpr(env, IPR_PERFMON, val, &oldval) == 1)
+ env->ir[0] = val;
+ break;
+ case 0x0000003A:
+ /* RDUSP */
+ if (cpu_alpha_mfpr(env, IPR_USP, &val) == 0)
+ env->ir[0] = val;
+ break;
+ case 0x0000003C:
+ /* WHAMI */
+ if (cpu_alpha_mfpr(env, IPR_WHAMI, &val) == 0)
+ env->ir[0] = val;
+ break;
+ case 0x0000003D:
+ /* RETSYS */
+ break;
+ case 0x0000003E:
+ /* WTINT */
+ break;
+ case 0x0000003F:
+ /* RTI */
+ if (cpu_alpha_mfpr(env, IPR_WHAMI, &val) == 0)
+ env->ir[0] = val;
+ break;
+ case 0x00000080:
+ /* BPT */
+ /* REQUIRED */
+ break;
+ case 0x00000081:
+ /* BUGCHK */
+ /* REQUIRED */
+ break;
+ case 0x00000083:
+ /* CALLSYS */
+ break;
+ case 0x00000086:
+ /* IMB */
+ /* REQUIRED */
+ /* Implemented as no-op */
+ break;
+ case 0x00000092:
+ /* URTI */
+ break;
+ case 0x0000009E:
+ /* RDUNIQUE */
+ /* REQUIRED */
+ break;
+ case 0x0000009F:
+ /* WRUNIQUE */
+ /* REQUIRED */
+ break;
+ case 0x000000AA:
+ /* GENTRAP */
+ /* REQUIRED */
+ break;
+ case 0x000000AE:
+ /* CLRFEN */
+ break;
+ default:
+ break;
+ }
+}
+
+void call_pal (CPUState *env)
+{
+ pal_handler_t *pal_handler = env->pal_handler;
+
+ switch (env->exception_index) {
+ case EXCP_RESET:
+ (*pal_handler->reset)(env);
+ break;
+ case EXCP_MCHK:
+ (*pal_handler->machine_check)(env);
+ break;
+ case EXCP_ARITH:
+ (*pal_handler->arithmetic)(env);
+ break;
+ case EXCP_INTERRUPT:
+ (*pal_handler->interrupt)(env);
+ break;
+ case EXCP_DFAULT:
+ (*pal_handler->dfault)(env);
+ break;
+ case EXCP_DTB_MISS_PAL:
+ (*pal_handler->dtb_miss_pal)(env);
+ break;
+ case EXCP_DTB_MISS_NATIVE:
+ (*pal_handler->dtb_miss_native)(env);
+ break;
+ case EXCP_UNALIGN:
+ (*pal_handler->unalign)(env);
+ break;
+ case EXCP_ITB_MISS:
+ (*pal_handler->itb_miss)(env);
+ break;
+ case EXCP_ITB_ACV:
+ (*pal_handler->itb_acv)(env);
+ break;
+ case EXCP_OPCDEC:
+ (*pal_handler->opcdec)(env);
+ break;
+ case EXCP_FEN:
+ (*pal_handler->fen)(env);
+ break;
+ default:
+ if (env->exception_index >= EXCP_CALL_PAL &&
+ env->exception_index < EXCP_CALL_PALP) {
+ /* Unprivileged PAL call */
+ (*pal_handler->call_pal)
+ (env, (env->exception_index - EXCP_CALL_PAL) >> 6);
+ } else if (env->exception_index >= EXCP_CALL_PALP &&
+ env->exception_index < EXCP_CALL_PALE) {
+ /* Privileged PAL call */
+ (*pal_handler->call_pal)
+ (env, ((env->exception_index - EXCP_CALL_PALP) >> 6) + 0x80);
+ } else {
+ /* Should never happen */
+ }
+ break;
+ }
+ env->ipr[IPR_EXC_ADDR] &= ~1;
+}
+
+void pal_init (CPUState *env)
+{
+ do_swappal(env, 0);
+}
+
+#if 0
+static uint64_t get_ptebase (CPUState *env, uint64_t vaddr)
+{
+ uint64_t virbnd, ptbr;
+
+ if ((env->features & FEATURE_VIRBND)) {
+ cpu_alpha_mfpr(env, IPR_VIRBND, &virbnd);
+ if (vaddr >= virbnd)
+ cpu_alpha_mfpr(env, IPR_SYSPTBR, &ptbr);
+ else
+ cpu_alpha_mfpr(env, IPR_PTBR, &ptbr);
+ } else {
+ cpu_alpha_mfpr(env, IPR_PTBR, &ptbr);
+ }
+
+ return ptbr;
+}
+
+static int get_page_bits (CPUState *env)
+{
+ /* XXX */
+ return 13;
+}
+
+static int get_pte (uint64_t *pfnp, int *zbitsp, int *protp,
+ uint64_t ptebase, int page_bits, uint64_t level,
+ int is_user, int rw)
+{
+ uint64_t pteaddr, pte, pfn;
+ uint8_t gh;
+ int ure, uwe, kre, kwe, foE, foR, foW, v, ret, ar;
+
+ pteaddr = (ptebase << page_bits) + (8 * level);
+ pte = ldq_raw(pteaddr);
+ /* Decode all interresting PTE fields */
+ pfn = pte >> 32;
+ uwe = (pte >> 13) & 1;
+ kwe = (pte >> 12) & 1;
+ ure = (pte >> 9) & 1;
+ kre = (pte >> 8) & 1;
+ gh = (pte >> 5) & 3;
+ foE = (pte >> 3) & 1;
+ foW = (pte >> 2) & 1;
+ foR = (pte >> 1) & 1;
+ v = pte & 1;
+ ret = 0;
+ if (!v)
+ ret = 0x1;
+ /* Check access rights */
+ ar = 0;
+ if (is_user) {
+ if (ure)
+ ar |= PAGE_READ;
+ if (uwe)
+ ar |= PAGE_WRITE;
+ if (rw == 1 && !uwe)
+ ret |= 0x2;
+ if (rw != 1 && !ure)
+ ret |= 0x2;
+ } else {
+ if (kre)
+ ar |= PAGE_READ;
+ if (kwe)
+ ar |= PAGE_WRITE;
+ if (rw == 1 && !kwe)
+ ret |= 0x2;
+ if (rw != 1 && !kre)
+ ret |= 0x2;
+ }
+ if (rw == 0 && foR)
+ ret |= 0x4;
+ if (rw == 2 && foE)
+ ret |= 0x8;
+ if (rw == 1 && foW)
+ ret |= 0xC;
+ *pfnp = pfn;
+ if (zbitsp != NULL)
+ *zbitsp = page_bits + (3 * gh);
+ if (protp != NULL)
+ *protp = ar;
+
+ return ret;
+}
+
+static int paddr_from_pte (uint64_t *paddr, int *zbitsp, int *prot,
+ uint64_t ptebase, int page_bits,
+ uint64_t vaddr, int is_user, int rw)
+{
+ uint64_t pfn, page_mask, lvl_mask, level1, level2, level3;
+ int lvl_bits, ret;
+
+ page_mask = (1ULL << page_bits) - 1ULL;
+ lvl_bits = page_bits - 3;
+ lvl_mask = (1ULL << lvl_bits) - 1ULL;
+ level3 = (vaddr >> page_bits) & lvl_mask;
+ level2 = (vaddr >> (page_bits + lvl_bits)) & lvl_mask;
+ level1 = (vaddr >> (page_bits + (2 * lvl_bits))) & lvl_mask;
+ /* Level 1 PTE */
+ ret = get_pte(&pfn, NULL, NULL, ptebase, page_bits, level1, 0, 0);
+ switch (ret) {
+ case 3:
+ /* Access violation */
+ return 2;
+ case 2:
+ /* translation not valid */
+ return 1;
+ default:
+ /* OK */
+ break;
+ }
+ /* Level 2 PTE */
+ ret = get_pte(&pfn, NULL, NULL, pfn, page_bits, level2, 0, 0);
+ switch (ret) {
+ case 3:
+ /* Access violation */
+ return 2;
+ case 2:
+ /* translation not valid */
+ return 1;
+ default:
+ /* OK */
+ break;
+ }
+ /* Level 3 PTE */
+ ret = get_pte(&pfn, zbitsp, prot, pfn, page_bits, level3, is_user, rw);
+ if (ret & 0x1) {
+ /* Translation not valid */
+ ret = 1;
+ } else if (ret & 2) {
+ /* Access violation */
+ ret = 2;
+ } else {
+ switch (ret & 0xC) {
+ case 0:
+ /* OK */
+ ret = 0;
+ break;
+ case 0x4:
+ /* Fault on read */
+ ret = 3;
+ break;
+ case 0x8:
+ /* Fault on execute */
+ ret = 4;
+ break;
+ case 0xC:
+ /* Fault on write */
+ ret = 5;
+ break;
+ }
+ }
+ *paddr = (pfn << page_bits) | (vaddr & page_mask);
+
+ return 0;
+}
+
+static int virtual_to_physical (CPUState *env, uint64_t *physp,
+ int *zbitsp, int *protp,
+ uint64_t virtual, int is_user, int rw)
+{
+ uint64_t sva, ptebase;
+ int seg, page_bits, ret;
+
+ sva = ((int64_t)(virtual << (64 - VA_BITS))) >> (64 - VA_BITS);
+ if (sva != virtual)
+ seg = -1;
+ else
+ seg = sva >> (VA_BITS - 2);
+ virtual &= ~(0xFFFFFC0000000000ULL << (VA_BITS - 43));
+ ptebase = get_ptebase(env, virtual);
+ page_bits = get_page_bits(env);
+ ret = 0;
+ switch (seg) {
+ case 0:
+ /* seg1: 3 levels of PTE */
+ ret = paddr_from_pte(physp, zbitsp, protp, ptebase, page_bits,
+ virtual, is_user, rw);
+ break;
+ case 1:
+ /* seg1: 2 levels of PTE */
+ ret = paddr_from_pte(physp, zbitsp, protp, ptebase, page_bits,
+ virtual, is_user, rw);
+ break;
+ case 2:
+ /* kernel segment */
+ if (is_user) {
+ ret = 2;
+ } else {
+ *physp = virtual;
+ }
+ break;
+ case 3:
+ /* seg1: TB mapped */
+ ret = paddr_from_pte(physp, zbitsp, protp, ptebase, page_bits,
+ virtual, is_user, rw);
+ break;
+ default:
+ ret = 1;
+ break;
+ }
+
+ return ret;
+}
+
+/* XXX: code provision */
+int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
+ int is_user, int is_softmmu)
+{
+ uint64_t physical, page_size, end;
+ int prot, zbits, ret;
+
+ if (env->user_mode_only) {
+ ret = 2;
+ } else {
+ ret = virtual_to_physical(env, &physical, &zbits, &prot,
+ address, is_user, rw);
+ }
+ switch (ret) {
+ case 0:
+ /* No fault */
+ page_size = 1ULL << zbits;
+ address &= ~(page_size - 1);
+ for (end = physical + page_size; physical < end; physical += 0x1000) {
+ ret = tlb_set_page(env, address, physical, prot,
+ is_user, is_softmmu);
+ address += 0x1000;
+ }
+ break;
+#if 0
+ case 1:
+ env->exception_index = EXCP_DFAULT;
+ env->ipr[IPR_EXC_ADDR] = address;
+ ret = 1;
+ break;
+ case 2:
+ env->exception_index = EXCP_ACCESS_VIOLATION;
+ env->ipr[IPR_EXC_ADDR] = address;
+ ret = 1;
+ break;
+ case 3:
+ env->exception_index = EXCP_FAULT_ON_READ;
+ env->ipr[IPR_EXC_ADDR] = address;
+ ret = 1;
+ break;
+ case 4:
+ env->exception_index = EXCP_FAULT_ON_EXECUTE;
+ env->ipr[IPR_EXC_ADDR] = address;
+ ret = 1;
+ case 5:
+ env->exception_index = EXCP_FAULT_ON_WRITE;
+ env->ipr[IPR_EXC_ADDR] = address;
+ ret = 1;
+#endif
+ default:
+ /* Should never happen */
+ env->exception_index = EXCP_MCHK;
+ env->ipr[IPR_EXC_ADDR] = address;
+ ret = 1;
+ break;
+ }
+
+ return ret;
+}
+#endif
+
+#else /* !defined (CONFIG_USER_ONLY) */
+void pal_init (CPUState *env)
+{
+}
+
+void call_pal (CPUState *env, int palcode)
+{
+ target_ulong ret;
+
+ printf("%s: palcode %02x\n", __func__, palcode);
+ if (logfile != NULL)
+ fprintf(logfile, "%s: palcode %02x\n", __func__, palcode);
+ switch (palcode) {
+ case 0x83:
+ /* CALLSYS */
+ printf("CALLSYS n " TARGET_FMT_ld "\n", env->ir[0]);
+ if (logfile != NULL)
+ fprintf(logfile, "CALLSYS n " TARGET_FMT_ld "\n", env->ir[0]);
+ ret = do_syscall(env, env->ir[IR_V0], env->ir[IR_A0], env->ir[IR_A1],
+ env->ir[IR_A2], env->ir[IR_A3], env->ir[IR_A4],
+ env->ir[IR_A5]);
+ env->ir[IR_A3] = ret;
+ if (ret > (target_ulong)(-515)) {
+ env->ir[IR_V0] = 1;
+ } else {
+ env->ir[IR_V0] = 0;
+ }
+ break;
+ case 0x9E:
+ /* RDUNIQUE */
+ env->ir[IR_V0] = env->unique;
+ printf("RDUNIQUE: " TARGET_FMT_lx "\n", env->unique);
+ break;
+ case 0x9F:
+ /* WRUNIQUE */
+ env->unique = env->ir[IR_A0];
+ printf("WRUNIQUE: " TARGET_FMT_lx "\n", env->unique);
+ break;
+ default:
+ printf("%s: unhandled palcode %02x\n", __func__, palcode);
+ if (logfile != NULL)
+ fprintf(logfile, "%s: unhandled palcode %02x\n",
+ __func__, palcode);
+ exit(1);
+ }
+}
+#endif
Modified: trunk/src/host/qemu-neo1973/hw/apb_pci.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/apb_pci.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/apb_pci.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -200,14 +200,14 @@
return bus_offset + irq_num;
}
-static void pci_apb_set_irq(void *pic, int irq_num, int level)
+static void pci_apb_set_irq(qemu_irq *pic, int irq_num, int level)
{
/* PCI IRQ map onto the first 32 INO. */
- pic_set_irq_new(pic, irq_num, level);
+ qemu_set_irq(pic[irq_num], level);
}
PCIBus *pci_apb_init(target_ulong special_base, target_ulong mem_base,
- void *pic)
+ qemu_irq *pic)
{
APBState *s;
PCIDevice *d;
Modified: trunk/src/host/qemu-neo1973/hw/apic.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/apic.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/apic.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -816,6 +816,7 @@
env->apic_state = s;
apic_init_ipi(s);
s->id = last_apic_id++;
+ env->cpuid_apic_id = s->id;
s->cpu_env = env;
s->apicbase = 0xfee00000 |
(s->id ? 0 : MSR_IA32_APICBASE_BSP) | MSR_IA32_APICBASE_ENABLE;
@@ -831,7 +832,7 @@
}
s->timer = qemu_new_timer(vm_clock, apic_timer, s);
- register_savevm("apic", 0, 1, apic_save, apic_load, s);
+ register_savevm("apic", 0, 2, apic_save, apic_load, s);
qemu_register_reset(apic_reset, s);
local_apics[s->id] = s;
Modified: trunk/src/host/qemu-neo1973/hw/arm_boot.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/arm_boot.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/arm_boot.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -24,8 +24,20 @@
0 /* Kernel entry point. Set by integratorcp_init. */
};
+static void main_cpu_reset(void *opaque)
+{
+ CPUState *env = opaque;
+
+ cpu_reset(env);
+ if (env->kernel_filename)
+ arm_load_kernel(env, env->ram_size, env->kernel_filename,
+ env->kernel_cmdline, env->initrd_filename,
+ env->board_id, env->loader_start);
+}
+
static void set_kernel_args(uint32_t ram_size, int initrd_size,
- const char *kernel_cmdline)
+ const char *kernel_cmdline,
+ target_phys_addr_t loader_start)
{
uint32_t *p;
@@ -40,12 +52,12 @@
stl_raw(p++, 4);
stl_raw(p++, 0x54410002);
stl_raw(p++, ram_size);
- stl_raw(p++, 0);
+ stl_raw(p++, loader_start);
if (initrd_size) {
/* ATAG_INITRD2 */
stl_raw(p++, 4);
stl_raw(p++, 0x54420005);
- stl_raw(p++, INITRD_LOAD_ADDR);
+ stl_raw(p++, loader_start + INITRD_LOAD_ADDR);
stl_raw(p++, initrd_size);
}
if (kernel_cmdline && *kernel_cmdline) {
@@ -64,42 +76,70 @@
stl_raw(p++, 0);
}
-void arm_load_kernel(int ram_size, const char *kernel_filename,
+void arm_load_kernel(CPUState *env, int ram_size, const char *kernel_filename,
const char *kernel_cmdline, const char *initrd_filename,
int board_id, target_phys_addr_t loader_start)
{
int kernel_size;
int initrd_size;
int n;
+ int is_linux = 0;
+ uint64_t elf_entry;
+ target_ulong entry;
/* Load the kernel. */
if (!kernel_filename) {
fprintf(stderr, "Kernel image must be specified\n");
exit(1);
}
- kernel_size = load_image(kernel_filename,
- phys_ram_base + KERNEL_LOAD_ADDR + S3C_SRAM_SIZE);////
+
+ if (!env->kernel_filename) {
+ env->ram_size = ram_size;
+ env->kernel_filename = kernel_filename;
+ env->kernel_cmdline = kernel_cmdline;
+ env->initrd_filename = initrd_filename;
+ env->board_id = board_id;
+ env->loader_start = loader_start;
+ qemu_register_reset(main_cpu_reset, env);
+ }
+ /* Assume that raw images are linux kernels, and ELF images are not. */
+ kernel_size = load_elf(kernel_filename, 0, &elf_entry, NULL, NULL);
+ entry = elf_entry;
if (kernel_size < 0) {
+ kernel_size = load_uboot(kernel_filename, &entry, &is_linux);
+ }
+ if (kernel_size < 0) {
+ kernel_size = load_image(kernel_filename,
+ phys_ram_base + KERNEL_LOAD_ADDR);
+ entry = loader_start + KERNEL_LOAD_ADDR;
+ is_linux = 1;
+ }
+ if (kernel_size < 0) {
fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename);
exit(1);
}
- if (initrd_filename) {
- initrd_size = load_image(initrd_filename,
- phys_ram_base + INITRD_LOAD_ADDR);
- if (initrd_size < 0) {
- fprintf(stderr, "qemu: could not load initrd '%s'\n",
- initrd_filename);
- exit(1);
+ if (!is_linux) {
+ /* Jump to the entry point. */
+ env->regs[15] = entry & 0xfffffffe;
+ env->thumb = entry & 1;
+ } else {
+ if (initrd_filename) {
+ initrd_size = load_image(initrd_filename,
+ phys_ram_base + INITRD_LOAD_ADDR);
+ if (initrd_size < 0) {
+ fprintf(stderr, "qemu: could not load initrd '%s'\n",
+ initrd_filename);
+ exit(1);
+ }
+ } else {
+ initrd_size = 0;
}
- } else {
- initrd_size = 0;
+ bootloader[1] |= board_id & 0xff;
+ bootloader[2] |= (board_id >> 8) & 0xff;
+ bootloader[5] = loader_start + KERNEL_ARGS_ADDR;
+ bootloader[6] = entry;
+ for (n = 0; n < sizeof(bootloader) / 4; n++)
+ stl_raw(phys_ram_base + (n * 4), bootloader[n]);
+ set_kernel_args(ram_size, initrd_size, kernel_cmdline, loader_start);
}
- bootloader[1] |= board_id & 0xff;
- bootloader[2] |= (board_id >> 8) & 0xff;
- bootloader[5] = loader_start + KERNEL_ARGS_ADDR;
- bootloader[6] = loader_start + KERNEL_LOAD_ADDR;
- for (n = 0; n < sizeof(bootloader) / 4; n++)
- stl_raw(phys_ram_base + (n * 4), bootloader[n]);
- set_kernel_args(ram_size, initrd_size, kernel_cmdline);
}
-
Modified: trunk/src/host/qemu-neo1973/hw/arm_gic.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/arm_gic.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/arm_gic.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -60,10 +60,8 @@
typedef struct gic_state
{
- arm_pic_handler handler;
uint32_t base;
- void *parent;
- int parent_irq;
+ qemu_irq parent_irq;
int enabled;
int cpu_enabled;
@@ -88,7 +86,7 @@
s->current_pending = 1023;
if (!s->enabled || !s->cpu_enabled) {
- pic_set_irq_new(s->parent, s->parent_irq, 0);
+ qemu_irq_lower(s->parent_irq);
return;
}
best_prio = 0x100;
@@ -102,12 +100,12 @@
}
}
if (best_prio > s->priority_mask) {
- pic_set_irq_new(s->parent, s->parent_irq, 0);
+ qemu_irq_lower(s->parent_irq);
} else {
s->current_pending = best_irq;
if (best_prio < s->running_priority) {
DPRINTF("Raised pending IRQ %d\n", best_irq);
- pic_set_irq_new(s->parent, s->parent_irq, 1);
+ qemu_irq_raise(s->parent_irq);
}
}
}
@@ -150,7 +148,7 @@
DPRINTF("ACK no pending IRQ\n");
return 1023;
}
- pic_set_irq_new(s->parent, s->parent_irq, 0);
+ qemu_irq_lower(s->parent_irq);
s->last_active[new_irq] = s->running_irq;
/* For level triggered interrupts we clear the pending bit while
the interrupt is active. */
@@ -520,16 +518,16 @@
s->cpu_enabled = 0;
}
-void *arm_gic_init(uint32_t base, void *parent, int parent_irq)
+qemu_irq *arm_gic_init(uint32_t base, qemu_irq parent_irq)
{
gic_state *s;
+ qemu_irq *qi;
int iomemtype;
s = (gic_state *)qemu_mallocz(sizeof(gic_state));
if (!s)
return NULL;
- s->handler = gic_set_irq;
- s->parent = parent;
+ qi = qemu_allocate_irqs(gic_set_irq, s, GIC_NIRQ);
s->parent_irq = parent_irq;
if (base != 0xffffffff) {
iomemtype = cpu_register_io_memory(0, gic_cpu_readfn,
@@ -543,5 +541,5 @@
s->base = 0;
}
gic_reset(s);
- return s;
+ return qi;
}
Modified: trunk/src/host/qemu-neo1973/hw/arm_pic.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/arm_pic.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/arm_pic.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -11,11 +11,6 @@
#include "arm_pic.h"
/* Stub functions for hardware that doesn't exist. */
-void pic_set_irq(int irq, int level)
-{
- cpu_abort(cpu_single_env, "pic_set_irq");
-}
-
void pic_info(void)
{
}
@@ -25,49 +20,29 @@
}
-void pic_set_irq_new(void *opaque, int irq, int level)
-{
- arm_pic_handler *p = (arm_pic_handler *)opaque;
- /* Call the real handler. */
- (*p)(opaque, irq, level);
-}
-
-/* Model the IRQ/FIQ CPU interrupt lines as a two input interrupt controller.
- Input 0 is IRQ and input 1 is FIQ. */
-typedef struct
-{
- arm_pic_handler handler;
- CPUState *cpu_env;
-} arm_pic_cpu_state;
-
+/* Input 0 is IRQ and input 1 is FIQ. */
static void arm_pic_cpu_handler(void *opaque, int irq, int level)
{
- arm_pic_cpu_state *s = (arm_pic_cpu_state *)opaque;
+ CPUState *env = (CPUState *)opaque;
switch (irq) {
case ARM_PIC_CPU_IRQ:
if (level)
- cpu_interrupt(s->cpu_env, CPU_INTERRUPT_HARD);
+ cpu_interrupt(env, CPU_INTERRUPT_HARD);
else
- cpu_reset_interrupt(s->cpu_env, CPU_INTERRUPT_HARD);
+ cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
break;
case ARM_PIC_CPU_FIQ:
if (level)
- cpu_interrupt(s->cpu_env, CPU_INTERRUPT_FIQ);
+ cpu_interrupt(env, CPU_INTERRUPT_FIQ);
else
- cpu_reset_interrupt(s->cpu_env, CPU_INTERRUPT_FIQ);
+ cpu_reset_interrupt(env, CPU_INTERRUPT_FIQ);
break;
default:
- cpu_abort(s->cpu_env, "arm_pic_cpu_handler: Bad interrput line %d\n",
- irq);
+ cpu_abort(env, "arm_pic_cpu_handler: Bad interrput line %d\n", irq);
}
}
-void *arm_pic_init_cpu(CPUState *env)
+qemu_irq *arm_pic_init_cpu(CPUState *env)
{
- arm_pic_cpu_state *s;
-
- s = (arm_pic_cpu_state *)malloc(sizeof(arm_pic_cpu_state));
- s->handler = arm_pic_cpu_handler;
- s->cpu_env = env;
- return s;
+ return qemu_allocate_irqs(arm_pic_cpu_handler, env, 2);
}
Modified: trunk/src/host/qemu-neo1973/hw/arm_pic.h
===================================================================
--- trunk/src/host/qemu-neo1973/hw/arm_pic.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/arm_pic.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -14,14 +14,10 @@
#ifndef ARM_INTERRUPT_H
#define ARM_INTERRUPT_H 1
-/* The first element of an individual PIC state structures should
- be a pointer to the handler routine. */
-typedef void (*arm_pic_handler)(void *opaque, int irq, int level);
-
/* The CPU is also modeled as an interrupt controller. */
#define ARM_PIC_CPU_IRQ 0
#define ARM_PIC_CPU_FIQ 1
-void *arm_pic_init_cpu(CPUState *env);
+qemu_irq *arm_pic_init_cpu(CPUState *env);
#endif /* !ARM_INTERRUPT_H */
Modified: trunk/src/host/qemu-neo1973/hw/arm_sysctl.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/arm_sysctl.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/arm_sysctl.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -149,7 +149,7 @@
if (s->lockval == LOCK_VALUE) {
s->resetlevel = val;
if (val & 0x100)
- cpu_abort(cpu_single_env, "Board reset\n");
+ qemu_system_reset_request ();
}
break;
case 0x44: /* PCICTL */
Modified: trunk/src/host/qemu-neo1973/hw/arm_timer.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/arm_timer.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/arm_timer.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -32,8 +32,7 @@
int raw_freq;
int freq;
int int_level;
- void *pic;
- int irq;
+ qemu_irq irq;
} arm_timer_state;
/* Calculate the new expiry time of the given timer. */
@@ -85,9 +84,9 @@
}
/* Update interrupts. */
if (s->int_level && (s->control & TIMER_CTRL_IE)) {
- pic_set_irq_new(s->pic, s->irq, 1);
+ qemu_irq_raise(s->irq);
} else {
- pic_set_irq_new(s->pic, s->irq, 0);
+ qemu_irq_lower(s->irq);
}
next = now;
@@ -215,12 +214,11 @@
arm_timer_update((arm_timer_state *)opaque, now);
}
-static void *arm_timer_init(uint32_t freq, void *pic, int irq)
+static void *arm_timer_init(uint32_t freq, qemu_irq irq)
{
arm_timer_state *s;
s = (arm_timer_state *)qemu_mallocz(sizeof(arm_timer_state));
- s->pic = pic;
s->irq = irq;
s->raw_freq = s->freq = 1000000;
s->control = TIMER_CTRL_IE;
@@ -233,26 +231,23 @@
/* ARM PrimeCell SP804 dual timer module.
Docs for this device don't seem to be publicly available. This
- implementation is based on gueswork, the linux kernel sources and the
+ implementation is based on guesswork, the linux kernel sources and the
Integrator/CP timer modules. */
typedef struct {
- /* Include a pseudo-PIC device to merge the two interrupt sources. */
- arm_pic_handler handler;
void *timer[2];
int level[2];
uint32_t base;
- /* The output PIC device. */
- void *pic;
- int irq;
+ qemu_irq irq;
} sp804_state;
+/* Merge the IRQs from the two component devices. */
static void sp804_set_irq(void *opaque, int irq, int level)
{
sp804_state *s = (sp804_state *)opaque;
s->level[irq] = level;
- pic_set_irq_new(s->pic, s->irq, s->level[0] || s->level[1]);
+ qemu_set_irq(s->irq, s->level[0] || s->level[1]);
}
static uint32_t sp804_read(void *opaque, target_phys_addr_t offset)
@@ -293,20 +288,20 @@
sp804_write
};
-void sp804_init(uint32_t base, void *pic, int irq)
+void sp804_init(uint32_t base, qemu_irq irq)
{
int iomemtype;
sp804_state *s;
+ qemu_irq *qi;
s = (sp804_state *)qemu_mallocz(sizeof(sp804_state));
- s->handler = sp804_set_irq;
+ qi = qemu_allocate_irqs(sp804_set_irq, s, 2);
s->base = base;
- s->pic = pic;
s->irq = irq;
/* ??? The timers are actually configurable between 32kHz and 1MHz, but
we don't implement that. */
- s->timer[0] = arm_timer_init(1000000, s, 0);
- s->timer[1] = arm_timer_init(1000000, s, 1);
+ s->timer[0] = arm_timer_init(1000000, qi[0]);
+ s->timer[1] = arm_timer_init(1000000, qi[1]);
iomemtype = cpu_register_io_memory(0, sp804_readfn,
sp804_writefn, s);
cpu_register_physical_memory(base, 0x00000fff, iomemtype);
@@ -362,7 +357,7 @@
icp_pit_write
};
-void icp_pit_init(uint32_t base, void *pic, int irq)
+void icp_pit_init(uint32_t base, qemu_irq *pic, int irq)
{
int iomemtype;
icp_pit_state *s;
@@ -370,10 +365,10 @@
s = (icp_pit_state *)qemu_mallocz(sizeof(icp_pit_state));
s->base = base;
/* Timer 0 runs at the system clock speed (40MHz). */
- s->timer[0] = arm_timer_init(40000000, pic, irq);
+ s->timer[0] = arm_timer_init(40000000, pic[irq]);
/* The other two timers run at 1MHz. */
- s->timer[1] = arm_timer_init(1000000, pic, irq + 1);
- s->timer[2] = arm_timer_init(1000000, pic, irq + 2);
+ s->timer[1] = arm_timer_init(1000000, pic[irq + 1]);
+ s->timer[2] = arm_timer_init(1000000, pic[irq + 2]);
iomemtype = cpu_register_io_memory(0, icp_pit_readfn,
icp_pit_writefn, s);
Modified: trunk/src/host/qemu-neo1973/hw/cirrus_vga.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/cirrus_vga.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/cirrus_vga.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -3193,6 +3193,9 @@
vga_common_init((VGAState *)s,
ds, vga_ram_base, vga_ram_offset, vga_ram_size);
cirrus_init_common(s, device_id, 1);
+
+ graphic_console_init(s->ds, s->update, s->invalidate, s->screen_dump, s);
+
s->pci_dev = (PCIDevice *)d;
/* setup memory space */
Modified: trunk/src/host/qemu-neo1973/hw/cs4231.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/cs4231.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/cs4231.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -47,9 +47,6 @@
#ifdef DEBUG_CS
#define DPRINTF(fmt, args...) \
do { printf("CS: " fmt , ##args); } while (0)
-#define pic_set_irq_new(intctl, irq, level) \
- do { printf("CS: set_irq(%d): %d\n", (irq), (level)); \
- pic_set_irq_new((intctl), (irq),(level));} while (0)
#else
#define DPRINTF(fmt, args...)
#endif
Modified: trunk/src/host/qemu-neo1973/hw/cuda.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/cuda.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/cuda.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -124,9 +124,7 @@
int data_in_index;
int data_out_index;
- SetIRQFunc *set_irq;
- int irq;
- void *irq_opaque;
+ qemu_irq irq;
uint8_t autopoll;
uint8_t data_in[128];
uint8_t data_out[16];
@@ -145,9 +143,9 @@
static void cuda_update_irq(CUDAState *s)
{
if (s->ifr & s->ier & (SR_INT | T1_INT)) {
- s->set_irq(s->irq_opaque, s->irq, 1);
+ qemu_irq_raise(s->irq);
} else {
- s->set_irq(s->irq_opaque, s->irq, 0);
+ qemu_irq_lower(s->irq);
}
}
@@ -630,13 +628,11 @@
&cuda_readl,
};
-int cuda_init(SetIRQFunc *set_irq, void *irq_opaque, int irq)
+int cuda_init(qemu_irq irq)
{
CUDAState *s = &cuda_state;
int cuda_mem_index;
- s->set_irq = set_irq;
- s->irq_opaque = irq_opaque;
s->irq = irq;
s->timers[0].index = 0;
Added: trunk/src/host/qemu-neo1973/hw/ds1225y.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/ds1225y.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/ds1225y.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,121 @@
+/*
+ * QEMU NVRAM emulation for DS1225Y chip
+ *
+ * Copyright (c) 2007 Hervé Poussineau
+ *
+ * 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 "vl.h"
+
+typedef enum
+{
+ none = 0,
+ readmode,
+ writemode,
+} nvram_open_mode;
+
+struct ds1225y_t
+{
+ target_ulong mem_base;
+ uint32_t capacity;
+ const char *filename;
+ QEMUFile *file;
+ nvram_open_mode open_mode;
+};
+
+static int ds1225y_set_to_mode(ds1225y_t *NVRAM, nvram_open_mode mode, const char *filemode)
+{
+ if (NVRAM->open_mode != mode)
+ {
+ if (NVRAM->file)
+ qemu_fclose(NVRAM->file);
+ NVRAM->file = qemu_fopen(NVRAM->filename, filemode);
+ NVRAM->open_mode = mode;
+ }
+ return (NVRAM->file != NULL);
+}
+
+static uint32_t nvram_readb (void *opaque, target_phys_addr_t addr)
+{
+ ds1225y_t *NVRAM = opaque;
+ int64_t pos;
+
+ pos = addr - NVRAM->mem_base;
+ if (addr >= NVRAM->capacity)
+ addr -= NVRAM->capacity;
+
+ if (!ds1225y_set_to_mode(NVRAM, readmode, "rb"))
+ return 0;
+ qemu_fseek(NVRAM->file, pos, SEEK_SET);
+ return (uint32_t)qemu_get_byte(NVRAM->file);
+}
+
+static void nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+ ds1225y_t *NVRAM = opaque;
+ int64_t pos;
+
+ pos = addr - NVRAM->mem_base;
+ if (ds1225y_set_to_mode(NVRAM, writemode, "wb"))
+ {
+ qemu_fseek(NVRAM->file, pos, SEEK_SET);
+ qemu_put_byte(NVRAM->file, (int)value);
+ }
+}
+
+static CPUReadMemoryFunc *nvram_read[] = {
+ &nvram_readb,
+ NULL,
+ NULL,
+};
+
+static CPUWriteMemoryFunc *nvram_write[] = {
+ &nvram_writeb,
+ NULL,
+ NULL,
+};
+
+static CPUWriteMemoryFunc *nvram_none[] = {
+ NULL,
+ NULL,
+ NULL,
+};
+
+/* Initialisation routine */
+ds1225y_t *ds1225y_init(target_ulong mem_base, const char *filename)
+{
+ ds1225y_t *s;
+ int mem_index1, mem_index2;
+
+ s = qemu_mallocz(sizeof(ds1225y_t));
+ if (!s)
+ return NULL;
+ s->mem_base = mem_base;
+ s->capacity = 0x2000; /* Fixed for ds1225y chip: 8K */
+ s->filename = filename;
+
+ /* Read/write memory */
+ mem_index1 = cpu_register_io_memory(0, nvram_read, nvram_write, s);
+ cpu_register_physical_memory(mem_base, s->capacity, mem_index1);
+ /* Read-only memory */
+ mem_index2 = cpu_register_io_memory(0, nvram_read, nvram_none, s);
+ cpu_register_physical_memory(mem_base + s->capacity, s->capacity, mem_index2);
+ return s;
+}
Added: trunk/src/host/qemu-neo1973/hw/eepro100.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/eepro100.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/eepro100.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,1714 @@
+/*
+ * QEMU i8255x (PRO100) emulation
+ *
+ * Copyright (c) 2006-2007 Stefan Weil
+ *
+ * Portions of the code are copies from grub / etherboot eepro100.c
+ * and linux e100.c.
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Tested features (i82559):
+ * PXE boot (i386) no valid link
+ * Linux networking (i386) ok
+ *
+ * Untested:
+ * non-i386 platforms
+ * Windows networking
+ *
+ * References:
+ *
+ * Intel 8255x 10/100 Mbps Ethernet Controller Family
+ * Open Source Software Developer Manual
+ */
+
+#if defined(TARGET_I386)
+# warning "PXE boot still not working!"
+#endif
+
+#include <assert.h>
+#include <stddef.h> /* offsetof */
+#include "vl.h"
+#include "eeprom93xx.h"
+
+/* Common declarations for all PCI devices. */
+
+#define PCI_VENDOR_ID 0x00 /* 16 bits */
+#define PCI_DEVICE_ID 0x02 /* 16 bits */
+#define PCI_COMMAND 0x04 /* 16 bits */
+#define PCI_STATUS 0x06 /* 16 bits */
+
+#define PCI_REVISION_ID 0x08 /* 8 bits */
+#define PCI_CLASS_CODE 0x0b /* 8 bits */
+#define PCI_SUBCLASS_CODE 0x0a /* 8 bits */
+#define PCI_HEADER_TYPE 0x0e /* 8 bits */
+
+#define PCI_BASE_ADDRESS_0 0x10 /* 32 bits */
+#define PCI_BASE_ADDRESS_1 0x14 /* 32 bits */
+#define PCI_BASE_ADDRESS_2 0x18 /* 32 bits */
+#define PCI_BASE_ADDRESS_3 0x1c /* 32 bits */
+#define PCI_BASE_ADDRESS_4 0x20 /* 32 bits */
+#define PCI_BASE_ADDRESS_5 0x24 /* 32 bits */
+
+#define PCI_CONFIG_8(offset, value) \
+ (pci_conf[offset] = (value))
+#define PCI_CONFIG_16(offset, value) \
+ (*(uint16_t *)&pci_conf[offset] = cpu_to_le16(value))
+#define PCI_CONFIG_32(offset, value) \
+ (*(uint32_t *)&pci_conf[offset] = cpu_to_le32(value))
+
+#define KiB 1024
+
+/* debug EEPRO100 card */
+//~ #define DEBUG_EEPRO100
+
+#ifdef DEBUG_EEPRO100
+#define logout(fmt, args...) fprintf(stderr, "EE100\t%-24s" fmt, __func__, ##args)
+#else
+#define logout(fmt, args...) ((void)0)
+#endif
+
+/* Set flags to 0 to disable debug output. */
+#define MDI 0
+
+#define TRACE(flag, command) ((flag) ? (command) : (void)0)
+
+#define missing(text) assert(!"feature is missing in this emulation: " text)
+
+#define MAX_ETH_FRAME_SIZE 1514
+
+/* This driver supports several different devices which are declared here. */
+#define i82551 0x82551
+#define i82557B 0x82557b
+#define i82557C 0x82557c
+#define i82558B 0x82558b
+#define i82559C 0x82559c
+#define i82559ER 0x82559e
+#define i82562 0x82562
+
+#define EEPROM_SIZE 64
+
+#define PCI_MEM_SIZE (4 * KiB)
+#define PCI_IO_SIZE 64
+#define PCI_FLASH_SIZE (128 * KiB)
+
+#define BIT(n) (1 << (n))
+#define BITS(n, m) (((0xffffffffU << (31 - n)) >> (31 - n + m)) << m)
+
+/* The SCB accepts the following controls for the Tx and Rx units: */
+#define CU_NOP 0x0000 /* No operation. */
+#define CU_START 0x0010 /* CU start. */
+#define CU_RESUME 0x0020 /* CU resume. */
+#define CU_STATSADDR 0x0040 /* Load dump counters address. */
+#define CU_SHOWSTATS 0x0050 /* Dump statistical counters. */
+#define CU_CMD_BASE 0x0060 /* Load CU base address. */
+#define CU_DUMPSTATS 0x0070 /* Dump and reset statistical counters. */
+#define CU_SRESUME 0x00a0 /* CU static resume. */
+
+#define RU_NOP 0x0000
+#define RX_START 0x0001
+#define RX_RESUME 0x0002
+#define RX_ABORT 0x0004
+#define RX_ADDR_LOAD 0x0006
+#define RX_RESUMENR 0x0007
+#define INT_MASK 0x0100
+#define DRVR_INT 0x0200 /* Driver generated interrupt. */
+
+typedef unsigned char bool;
+
+/* Offsets to the various registers.
+ All accesses need not be longword aligned. */
+enum speedo_offsets {
+ SCBStatus = 0,
+ SCBAck = 1,
+ SCBCmd = 2, /* Rx/Command Unit command and status. */
+ SCBIntmask = 3,
+ SCBPointer = 4, /* General purpose pointer. */
+ SCBPort = 8, /* Misc. commands and operands. */
+ SCBflash = 12, SCBeeprom = 14, /* EEPROM and flash memory control. */
+ SCBCtrlMDI = 16, /* MDI interface control. */
+ SCBEarlyRx = 20, /* Early receive byte count. */
+};
+
+/* A speedo3 transmit buffer descriptor with two buffers... */
+typedef struct {
+ uint16_t status;
+ uint16_t command;
+ uint32_t link; /* void * */
+ uint32_t tx_desc_addr; /* transmit buffer decsriptor array address. */
+ uint16_t tcb_bytes; /* transmit command block byte count (in lower 14 bits */
+ uint8_t tx_threshold; /* transmit threshold */
+ uint8_t tbd_count; /* TBD number */
+ //~ /* This constitutes two "TBD" entries: hdr and data */
+ //~ uint32_t tx_buf_addr0; /* void *, header of frame to be transmitted. */
+ //~ int32_t tx_buf_size0; /* Length of Tx hdr. */
+ //~ uint32_t tx_buf_addr1; /* void *, data to be transmitted. */
+ //~ int32_t tx_buf_size1; /* Length of Tx data. */
+} eepro100_tx_t;
+
+/* Receive frame descriptor. */
+typedef struct {
+ int16_t status;
+ uint16_t command;
+ uint32_t link; /* struct RxFD * */
+ uint32_t rx_buf_addr; /* void * */
+ uint16_t count;
+ uint16_t size;
+ char packet[MAX_ETH_FRAME_SIZE + 4];
+} eepro100_rx_t;
+
+typedef struct {
+ uint32_t tx_good_frames, tx_max_collisions, tx_late_collisions,
+ tx_underruns, tx_lost_crs, tx_deferred, tx_single_collisions,
+ tx_multiple_collisions, tx_total_collisions;
+ uint32_t rx_good_frames, rx_crc_errors, rx_alignment_errors,
+ rx_resource_errors, rx_overrun_errors, rx_cdt_errors,
+ rx_short_frame_errors;
+ uint32_t fc_xmt_pause, fc_rcv_pause, fc_rcv_unsupported;
+ uint16_t xmt_tco_frames, rcv_tco_frames;
+ uint32_t complete;
+} eepro100_stats_t;
+
+typedef enum {
+ cu_idle = 0,
+ cu_suspended = 1,
+ cu_active = 2,
+ cu_lpq_active = 2,
+ cu_hqp_active = 3
+} cu_state_t;
+
+typedef enum {
+ ru_idle = 0,
+ ru_suspended = 1,
+ ru_no_resources = 2,
+ ru_ready = 4
+} ru_state_t;
+
+#if defined(__BIG_ENDIAN_BITFIELD)
+#define X(a,b) b,a
+#else
+#define X(a,b) a,b
+#endif
+
+typedef struct {
+#if 1
+ uint8_t cmd;
+ uint32_t start;
+ uint32_t stop;
+ uint8_t boundary;
+ uint8_t tsr;
+ uint8_t tpsr;
+ uint16_t tcnt;
+ uint16_t rcnt;
+ uint32_t rsar;
+ uint8_t rsr;
+ uint8_t rxcr;
+ uint8_t isr;
+ uint8_t dcfg;
+ uint8_t imr;
+ uint8_t phys[6]; /* mac address */
+ uint8_t curpag;
+ uint8_t mult[8]; /* multicast mask array */
+ int mmio_index;
+ PCIDevice *pci_dev;
+ VLANClientState *vc;
+#endif
+ uint8_t scb_stat; /* SCB stat/ack byte */
+ uint8_t int_stat; /* PCI interrupt status */
+ uint32_t region[3]; /* PCI region addresses */
+ uint8_t macaddr[6];
+ uint32_t statcounter[19];
+ uint16_t mdimem[32];
+ eeprom_t *eeprom;
+ uint32_t device; /* device variant */
+ uint32_t pointer;
+ /* (cu_base + cu_offset) address the next command block in the command block list. */
+ uint32_t cu_base; /* CU base address */
+ uint32_t cu_offset; /* CU address offset */
+ /* (ru_base + ru_offset) address the RFD in the Receive Frame Area. */
+ uint32_t ru_base; /* RU base address */
+ uint32_t ru_offset; /* RU address offset */
+ uint32_t statsaddr; /* pointer to eepro100_stats_t */
+ eepro100_stats_t statistics; /* statistical counters */
+#if 0
+ uint16_t status;
+#endif
+
+ /* Configuration bytes. */
+ uint8_t configuration[22];
+
+ /* Data in mem is always in the byte order of the controller (le). */
+ uint8_t mem[PCI_MEM_SIZE];
+} EEPRO100State;
+
+/* Default values for MDI (PHY) registers */
+static const uint16_t eepro100_mdi_default[] = {
+ /* MDI Registers 0 - 6, 7 */
+ 0x3000, 0x780d, 0x02a8, 0x0154, 0x05e1, 0x0000, 0x0000, 0x0000,
+ /* MDI Registers 8 - 15 */
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ /* MDI Registers 16 - 31 */
+ 0x0003, 0x0000, 0x0001, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+};
+
+/* Readonly mask for MDI (PHY) registers */
+static const uint16_t eepro100_mdi_mask[] = {
+ 0x0000, 0xffff, 0xffff, 0xffff, 0xc01f, 0xffff, 0xffff, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0fff, 0x0000, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
+ 0xffff, 0xffff, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+};
+
+#define POLYNOMIAL 0x04c11db6
+
+/* From FreeBSD */
+/* XXX: optimize */
+static int compute_mcast_idx(const uint8_t * ep)
+{
+ uint32_t crc;
+ int carry, i, j;
+ uint8_t b;
+
+ crc = 0xffffffff;
+ for (i = 0; i < 6; i++) {
+ b = *ep++;
+ for (j = 0; j < 8; j++) {
+ carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01);
+ crc <<= 1;
+ b >>= 1;
+ if (carry)
+ crc = ((crc ^ POLYNOMIAL) | carry);
+ }
+ }
+ return (crc >> 26);
+}
+
+#if defined(DEBUG_EEPRO100)
+static const char *nic_dump(const uint8_t * buf, unsigned size)
+{
+ static char dump[3 * 16 + 1];
+ char *p = &dump[0];
+ if (size > 16)
+ size = 16;
+ while (size-- > 0) {
+ p += sprintf(p, " %02x", *buf++);
+ }
+ return dump;
+}
+#endif /* DEBUG_EEPRO100 */
+
+enum scb_stat_ack {
+ stat_ack_not_ours = 0x00,
+ stat_ack_sw_gen = 0x04,
+ stat_ack_rnr = 0x10,
+ stat_ack_cu_idle = 0x20,
+ stat_ack_frame_rx = 0x40,
+ stat_ack_cu_cmd_done = 0x80,
+ stat_ack_not_present = 0xFF,
+ stat_ack_rx = (stat_ack_sw_gen | stat_ack_rnr | stat_ack_frame_rx),
+ stat_ack_tx = (stat_ack_cu_idle | stat_ack_cu_cmd_done),
+};
+
+static void disable_interrupt(EEPRO100State * s)
+{
+ if (s->int_stat) {
+ logout("interrupt disabled\n");
+ qemu_irq_lower(s->pci_dev->irq[0]);
+ s->int_stat = 0;
+ }
+}
+
+static void enable_interrupt(EEPRO100State * s)
+{
+ if (!s->int_stat) {
+ logout("interrupt enabled\n");
+ qemu_irq_raise(s->pci_dev->irq[0]);
+ s->int_stat = 1;
+ }
+}
+
+static void eepro100_acknowledge(EEPRO100State * s)
+{
+ s->scb_stat &= ~s->mem[SCBAck];
+ s->mem[SCBAck] = s->scb_stat;
+ if (s->scb_stat == 0) {
+ disable_interrupt(s);
+ }
+}
+
+static void eepro100_interrupt(EEPRO100State * s, uint8_t stat)
+{
+ uint8_t mask = ~s->mem[SCBIntmask];
+ s->mem[SCBAck] |= stat;
+ stat = s->scb_stat = s->mem[SCBAck];
+ stat &= (mask | 0x0f);
+ //~ stat &= (~s->mem[SCBIntmask] | 0x0xf);
+ if (stat && (mask & 0x01)) {
+ /* SCB mask and SCB Bit M do not disable interrupt. */
+ enable_interrupt(s);
+ } else if (s->int_stat) {
+ disable_interrupt(s);
+ }
+}
+
+static void eepro100_cx_interrupt(EEPRO100State * s)
+{
+ /* CU completed action command. */
+ /* Transmit not ok (82557 only, not in emulation). */
+ eepro100_interrupt(s, 0x80);
+}
+
+static void eepro100_cna_interrupt(EEPRO100State * s)
+{
+ /* CU left the active state. */
+ eepro100_interrupt(s, 0x20);
+}
+
+static void eepro100_fr_interrupt(EEPRO100State * s)
+{
+ /* RU received a complete frame. */
+ eepro100_interrupt(s, 0x40);
+}
+
+#if 0
+static void eepro100_rnr_interrupt(EEPRO100State * s)
+{
+ /* RU is not ready. */
+ eepro100_interrupt(s, 0x10);
+}
+#endif
+
+static void eepro100_mdi_interrupt(EEPRO100State * s)
+{
+ /* MDI completed read or write cycle. */
+ eepro100_interrupt(s, 0x08);
+}
+
+static void eepro100_swi_interrupt(EEPRO100State * s)
+{
+ /* Software has requested an interrupt. */
+ eepro100_interrupt(s, 0x04);
+}
+
+#if 0
+static void eepro100_fcp_interrupt(EEPRO100State * s)
+{
+ /* Flow control pause interrupt (82558 and later). */
+ eepro100_interrupt(s, 0x01);
+}
+#endif
+
+static void pci_reset(EEPRO100State * s)
+{
+ uint32_t device = s->device;
+ uint8_t *pci_conf = s->pci_dev->config;
+
+ logout("%p\n", s);
+
+ /* PCI Vendor ID */
+ PCI_CONFIG_16(PCI_VENDOR_ID, 0x8086);
+ /* PCI Device ID */
+ PCI_CONFIG_16(PCI_DEVICE_ID, 0x1209);
+ /* PCI Command */
+ PCI_CONFIG_16(PCI_COMMAND, 0x0000);
+ /* PCI Status */
+ PCI_CONFIG_16(PCI_STATUS, 0x2800);
+ /* PCI Revision ID */
+ PCI_CONFIG_8(PCI_REVISION_ID, 0x08);
+ /* PCI Class Code */
+ PCI_CONFIG_8(0x09, 0x00);
+ PCI_CONFIG_8(PCI_SUBCLASS_CODE, 0x00); // ethernet network controller
+ PCI_CONFIG_8(PCI_CLASS_CODE, 0x02); // network controller
+ /* PCI Cache Line Size */
+ /* check cache line size!!! */
+ //~ PCI_CONFIG_8(0x0c, 0x00);
+ /* PCI Latency Timer */
+ PCI_CONFIG_8(0x0d, 0x20); // latency timer = 32 clocks
+ /* PCI Header Type */
+ /* BIST (built-in self test) */
+#if defined(TARGET_I386)
+// !!! workaround for buggy bios
+//~ #define PCI_ADDRESS_SPACE_MEM_PREFETCH 0
+#endif
+#if 0
+ /* PCI Base Address Registers */
+ /* CSR Memory Mapped Base Address */
+ PCI_CONFIG_32(PCI_BASE_ADDRESS_0,
+ PCI_ADDRESS_SPACE_MEM | PCI_ADDRESS_SPACE_MEM_PREFETCH);
+ /* CSR I/O Mapped Base Address */
+ PCI_CONFIG_32(PCI_BASE_ADDRESS_1, PCI_ADDRESS_SPACE_IO);
+#if 0
+ /* Flash Memory Mapped Base Address */
+ PCI_CONFIG_32(PCI_BASE_ADDRESS_2, 0xfffe0000 | PCI_ADDRESS_SPACE_MEM);
+#endif
+#endif
+ /* Expansion ROM Base Address (depends on boot disable!!!) */
+ PCI_CONFIG_32(0x30, 0x00000000);
+ /* Capability Pointer */
+ PCI_CONFIG_8(0x34, 0xdc);
+ /* Interrupt Pin */
+ PCI_CONFIG_8(0x3d, 1); // interrupt pin 0
+ /* Minimum Grant */
+ PCI_CONFIG_8(0x3e, 0x08);
+ /* Maximum Latency */
+ PCI_CONFIG_8(0x3f, 0x18);
+ /* Power Management Capabilities / Next Item Pointer / Capability ID */
+ PCI_CONFIG_32(0xdc, 0x7e210001);
+
+ switch (device) {
+ case i82551:
+ //~ PCI_CONFIG_16(PCI_DEVICE_ID, 0x1209);
+ PCI_CONFIG_8(PCI_REVISION_ID, 0x0f);
+ break;
+ case i82557B:
+ PCI_CONFIG_16(PCI_DEVICE_ID, 0x1229);
+ PCI_CONFIG_8(PCI_REVISION_ID, 0x02);
+ break;
+ case i82557C:
+ PCI_CONFIG_16(PCI_DEVICE_ID, 0x1229);
+ PCI_CONFIG_8(PCI_REVISION_ID, 0x03);
+ break;
+ case i82558B:
+ PCI_CONFIG_16(PCI_DEVICE_ID, 0x1229);
+ PCI_CONFIG_16(PCI_STATUS, 0x2810);
+ PCI_CONFIG_8(PCI_REVISION_ID, 0x05);
+ break;
+ case i82559C:
+ PCI_CONFIG_16(PCI_DEVICE_ID, 0x1229);
+ PCI_CONFIG_16(PCI_STATUS, 0x2810);
+ //~ PCI_CONFIG_8(PCI_REVISION_ID, 0x08);
+ break;
+ case i82559ER:
+ //~ PCI_CONFIG_16(PCI_DEVICE_ID, 0x1209);
+ PCI_CONFIG_16(PCI_STATUS, 0x2810);
+ PCI_CONFIG_8(PCI_REVISION_ID, 0x09);
+ break;
+ //~ PCI_CONFIG_16(PCI_DEVICE_ID, 0x1029);
+ //~ PCI_CONFIG_16(PCI_DEVICE_ID, 0x1030); /* 82559 InBusiness 10/100 */
+ default:
+ logout("Device %X is undefined!\n", device);
+ }
+
+ if (device == i82557C || device == i82558B || device == i82559C) {
+ logout("Get device id and revision from EEPROM!!!\n");
+ }
+}
+
+static void nic_selective_reset(EEPRO100State * s)
+{
+ size_t i;
+ uint16_t *eeprom_contents = eeprom93xx_data(s->eeprom);
+ //~ eeprom93xx_reset(s->eeprom);
+ memcpy(eeprom_contents, s->macaddr, 6);
+ eeprom_contents[0xa] = 0x4000;
+ uint16_t sum = 0;
+ for (i = 0; i < EEPROM_SIZE - 1; i++) {
+ sum += eeprom_contents[i];
+ }
+ eeprom_contents[EEPROM_SIZE - 1] = 0xbaba - sum;
+
+ memset(s->mem, 0, sizeof(s->mem));
+ uint32_t val = BIT(21);
+ memcpy(&s->mem[SCBCtrlMDI], &val, sizeof(val));
+
+ assert(sizeof(s->mdimem) == sizeof(eepro100_mdi_default));
+ memcpy(&s->mdimem[0], &eepro100_mdi_default[0], sizeof(s->mdimem));
+}
+
+static void nic_reset(void *opaque)
+{
+ EEPRO100State *s = (EEPRO100State *) opaque;
+ logout("%p\n", s);
+ static int first;
+ if (!first) {
+ first = 1;
+ }
+ nic_selective_reset(s);
+}
+
+#if defined(DEBUG_EEPRO100)
+static const char *reg[PCI_IO_SIZE / 4] = {
+ "Command/Status",
+ "General Pointer",
+ "Port",
+ "EEPROM/Flash Control",
+ "MDI Control",
+ "Receive DMA Byte Count",
+ "Flow control register",
+ "General Status/Control"
+};
+
+static char *regname(uint32_t addr)
+{
+ static char buf[16];
+ if (addr < PCI_IO_SIZE) {
+ const char *r = reg[addr / 4];
+ if (r != 0) {
+ sprintf(buf, "%s+%u", r, addr % 4);
+ } else {
+ sprintf(buf, "0x%02x", addr);
+ }
+ } else {
+ sprintf(buf, "??? 0x%08x", addr);
+ }
+ return buf;
+}
+#endif /* DEBUG_EEPRO100 */
+
+#if 0
+static uint16_t eepro100_read_status(EEPRO100State * s)
+{
+ uint16_t val = s->status;
+ logout("val=0x%04x\n", val);
+ return val;
+}
+
+static void eepro100_write_status(EEPRO100State * s, uint16_t val)
+{
+ logout("val=0x%04x\n", val);
+ s->status = val;
+}
+#endif
+
+/*****************************************************************************
+ *
+ * Command emulation.
+ *
+ ****************************************************************************/
+
+#if 0
+static uint16_t eepro100_read_command(EEPRO100State * s)
+{
+ uint16_t val = 0xffff;
+ //~ logout("val=0x%04x\n", val);
+ return val;
+}
+#endif
+
+/* Commands that can be put in a command list entry. */
+enum commands {
+ CmdNOp = 0,
+ CmdIASetup = 1,
+ CmdConfigure = 2,
+ CmdMulticastList = 3,
+ CmdTx = 4,
+ CmdTDR = 5, /* load microcode */
+ CmdDump = 6,
+ CmdDiagnose = 7,
+
+ /* And some extra flags: */
+ CmdSuspend = 0x4000, /* Suspend after completion. */
+ CmdIntr = 0x2000, /* Interrupt after completion. */
+ CmdTxFlex = 0x0008, /* Use "Flexible mode" for CmdTx command. */
+};
+
+static cu_state_t get_cu_state(EEPRO100State * s)
+{
+ return ((s->mem[SCBStatus] >> 6) & 0x03);
+}
+
+static void set_cu_state(EEPRO100State * s, cu_state_t state)
+{
+ s->mem[SCBStatus] = (s->mem[SCBStatus] & 0x3f) + (state << 6);
+}
+
+static ru_state_t get_ru_state(EEPRO100State * s)
+{
+ return ((s->mem[SCBStatus] >> 2) & 0x0f);
+}
+
+static void set_ru_state(EEPRO100State * s, ru_state_t state)
+{
+ s->mem[SCBStatus] = (s->mem[SCBStatus] & 0xc3) + (state << 2);
+}
+
+static void dump_statistics(EEPRO100State * s)
+{
+ /* Dump statistical data. Most data is never changed by the emulation
+ * and always 0, so we first just copy the whole block and then those
+ * values which really matter.
+ * Number of data should check configuration!!!
+ */
+ cpu_physical_memory_write(s->statsaddr, (uint8_t *) & s->statistics, 64);
+ stl_phys(s->statsaddr + 0, s->statistics.tx_good_frames);
+ stl_phys(s->statsaddr + 36, s->statistics.rx_good_frames);
+ stl_phys(s->statsaddr + 48, s->statistics.rx_resource_errors);
+ stl_phys(s->statsaddr + 60, s->statistics.rx_short_frame_errors);
+ //~ stw_phys(s->statsaddr + 76, s->statistics.xmt_tco_frames);
+ //~ stw_phys(s->statsaddr + 78, s->statistics.rcv_tco_frames);
+ //~ missing("CU dump statistical counters");
+}
+
+static void eepro100_cu_command(EEPRO100State * s, uint8_t val)
+{
+ eepro100_tx_t tx;
+ uint32_t cb_address;
+ switch (val) {
+ case CU_NOP:
+ /* No operation. */
+ break;
+ case CU_START:
+ if (get_cu_state(s) != cu_idle) {
+ /* Intel documentation says that CU must be idle for the CU
+ * start command. Intel driver for Linux also starts the CU
+ * from suspended state. */
+ logout("CU state is %u, should be %u\n", get_cu_state(s), cu_idle);
+ //~ assert(!"wrong CU state");
+ }
+ set_cu_state(s, cu_active);
+ s->cu_offset = s->pointer;
+ next_command:
+ cb_address = s->cu_base + s->cu_offset;
+ cpu_physical_memory_read(cb_address, (uint8_t *) & tx, sizeof(tx));
+ uint16_t status = le16_to_cpu(tx.status);
+ uint16_t command = le16_to_cpu(tx.command);
+ logout
+ ("val=0x%02x (cu start), status=0x%04x, command=0x%04x, link=0x%08x\n",
+ val, status, command, tx.link);
+ bool bit_el = ((command & 0x8000) != 0);
+ bool bit_s = ((command & 0x4000) != 0);
+ bool bit_i = ((command & 0x2000) != 0);
+ bool bit_nc = ((command & 0x0010) != 0);
+ //~ bool bit_sf = ((command & 0x0008) != 0);
+ uint16_t cmd = command & 0x0007;
+ s->cu_offset = le32_to_cpu(tx.link);
+ switch (cmd) {
+ case CmdNOp:
+ /* Do nothing. */
+ break;
+ case CmdIASetup:
+ cpu_physical_memory_read(cb_address + 8, &s->macaddr[0], 6);
+ logout("macaddr: %s\n", nic_dump(&s->macaddr[0], 6));
+ break;
+ case CmdConfigure:
+ cpu_physical_memory_read(cb_address + 8, &s->configuration[0],
+ sizeof(s->configuration));
+ logout("configuration: %s\n", nic_dump(&s->configuration[0], 16));
+ break;
+ case CmdMulticastList:
+ //~ missing("multicast list");
+ break;
+ case CmdTx:
+ (void)0;
+ uint32_t tbd_array = le32_to_cpu(tx.tx_desc_addr);
+ uint16_t tcb_bytes = (le16_to_cpu(tx.tcb_bytes) & 0x3fff);
+ logout
+ ("transmit, TBD array address 0x%08x, TCB byte count 0x%04x, TBD count %u\n",
+ tbd_array, tcb_bytes, tx.tbd_count);
+ assert(!bit_nc);
+ //~ assert(!bit_sf);
+ assert(tcb_bytes <= 2600);
+ /* Next assertion fails for local configuration. */
+ //~ assert((tcb_bytes > 0) || (tbd_array != 0xffffffff));
+ if (!((tcb_bytes > 0) || (tbd_array != 0xffffffff))) {
+ logout
+ ("illegal values of TBD array address and TCB byte count!\n");
+ }
+ uint8_t buf[MAX_ETH_FRAME_SIZE + 4];
+ uint16_t size = 0;
+ uint32_t tbd_address = cb_address + 0x10;
+ assert(tcb_bytes <= sizeof(buf));
+ while (size < tcb_bytes) {
+ uint32_t tx_buffer_address = ldl_phys(tbd_address);
+ uint16_t tx_buffer_size = lduw_phys(tbd_address + 4);
+ //~ uint16_t tx_buffer_el = lduw_phys(tbd_address + 6);
+ tbd_address += 8;
+ logout
+ ("TBD (simplified mode): buffer address 0x%08x, size 0x%04x\n",
+ tx_buffer_address, tx_buffer_size);
+ cpu_physical_memory_read(tx_buffer_address, &buf[size],
+ tx_buffer_size);
+ size += tx_buffer_size;
+ }
+ if (tbd_array == 0xffffffff) {
+ /* Simplified mode. Was already handled by code above. */
+ } else {
+ /* Flexible mode. */
+ uint8_t tbd_count = 0;
+ if (!(s->configuration[6] & BIT(4))) {
+ /* Extended TCB. */
+ assert(tcb_bytes == 0);
+ for (; tbd_count < 2; tbd_count++) {
+ uint32_t tx_buffer_address = ldl_phys(tbd_address);
+ uint16_t tx_buffer_size = lduw_phys(tbd_address + 4);
+ uint16_t tx_buffer_el = lduw_phys(tbd_address + 6);
+ tbd_address += 8;
+ logout
+ ("TBD (extended mode): buffer address 0x%08x, size 0x%04x\n",
+ tx_buffer_address, tx_buffer_size);
+ cpu_physical_memory_read(tx_buffer_address, &buf[size],
+ tx_buffer_size);
+ size += tx_buffer_size;
+ if (tx_buffer_el & 1) {
+ break;
+ }
+ }
+ }
+ tbd_address = tbd_array;
+ for (; tbd_count < tx.tbd_count; tbd_count++) {
+ uint32_t tx_buffer_address = ldl_phys(tbd_address);
+ uint16_t tx_buffer_size = lduw_phys(tbd_address + 4);
+ uint16_t tx_buffer_el = lduw_phys(tbd_address + 6);
+ tbd_address += 8;
+ logout
+ ("TBD (flexible mode): buffer address 0x%08x, size 0x%04x\n",
+ tx_buffer_address, tx_buffer_size);
+ cpu_physical_memory_read(tx_buffer_address, &buf[size],
+ tx_buffer_size);
+ size += tx_buffer_size;
+ if (tx_buffer_el & 1) {
+ break;
+ }
+ }
+ }
+ qemu_send_packet(s->vc, buf, size);
+ s->statistics.tx_good_frames++;
+ /* Transmit with bad status would raise an CX/TNO interrupt.
+ * (82557 only). Emulation never has bad status. */
+ //~ eepro100_cx_interrupt(s);
+ break;
+ case CmdTDR:
+ logout("load microcode\n");
+ /* Starting with offset 8, the command contains
+ * 64 dwords microcode which we just ignore here. */
+ break;
+ default:
+ missing("undefined command");
+ }
+ /* Write new status (success). */
+ stw_phys(cb_address, status | 0x8000 | 0x2000);
+ if (bit_i) {
+ /* CU completed action. */
+ eepro100_cx_interrupt(s);
+ }
+ if (bit_el) {
+ /* CU becomes idle. */
+ set_cu_state(s, cu_idle);
+ eepro100_cna_interrupt(s);
+ } else if (bit_s) {
+ /* CU becomes suspended. */
+ set_cu_state(s, cu_suspended);
+ eepro100_cna_interrupt(s);
+ } else {
+ /* More entries in list. */
+ logout("CU list with at least one more entry\n");
+ goto next_command;
+ }
+ logout("CU list empty\n");
+ /* List is empty. Now CU is idle or suspended. */
+ break;
+ case CU_RESUME:
+ if (get_cu_state(s) != cu_suspended) {
+ logout("bad CU resume from CU state %u\n", get_cu_state(s));
+ /* Workaround for bad Linux eepro100 driver which resumes
+ * from idle state. */
+ //~ missing("cu resume");
+ set_cu_state(s, cu_suspended);
+ }
+ if (get_cu_state(s) == cu_suspended) {
+ logout("CU resuming\n");
+ set_cu_state(s, cu_active);
+ goto next_command;
+ }
+ break;
+ case CU_STATSADDR:
+ /* Load dump counters address. */
+ s->statsaddr = s->pointer;
+ logout("val=0x%02x (status address)\n", val);
+ break;
+ case CU_SHOWSTATS:
+ /* Dump statistical counters. */
+ dump_statistics(s);
+ break;
+ case CU_CMD_BASE:
+ /* Load CU base. */
+ logout("val=0x%02x (CU base address)\n", val);
+ s->cu_base = s->pointer;
+ break;
+ case CU_DUMPSTATS:
+ /* Dump and reset statistical counters. */
+ dump_statistics(s);
+ memset(&s->statistics, 0, sizeof(s->statistics));
+ break;
+ case CU_SRESUME:
+ /* CU static resume. */
+ missing("CU static resume");
+ break;
+ default:
+ missing("Undefined CU command");
+ }
+}
+
+static void eepro100_ru_command(EEPRO100State * s, uint8_t val)
+{
+ switch (val) {
+ case RU_NOP:
+ /* No operation. */
+ break;
+ case RX_START:
+ /* RU start. */
+ if (get_ru_state(s) != ru_idle) {
+ logout("RU state is %u, should be %u\n", get_ru_state(s), ru_idle);
+ //~ assert(!"wrong RU state");
+ }
+ set_ru_state(s, ru_ready);
+ s->ru_offset = s->pointer;
+ logout("val=0x%02x (rx start)\n", val);
+ break;
+ case RX_RESUME:
+ /* Restart RU. */
+ if (get_ru_state(s) != ru_suspended) {
+ logout("RU state is %u, should be %u\n", get_ru_state(s),
+ ru_suspended);
+ //~ assert(!"wrong RU state");
+ }
+ set_ru_state(s, ru_ready);
+ break;
+ case RX_ADDR_LOAD:
+ /* Load RU base. */
+ logout("val=0x%02x (RU base address)\n", val);
+ s->ru_base = s->pointer;
+ break;
+ default:
+ logout("val=0x%02x (undefined RU command)\n", val);
+ missing("Undefined SU command");
+ }
+}
+
+static void eepro100_write_command(EEPRO100State * s, uint8_t val)
+{
+ eepro100_ru_command(s, val & 0x0f);
+ eepro100_cu_command(s, val & 0xf0);
+ if ((val) == 0) {
+ logout("val=0x%02x\n", val);
+ }
+ /* Clear command byte after command was accepted. */
+ s->mem[SCBCmd] = 0;
+}
+
+/*****************************************************************************
+ *
+ * EEPROM emulation.
+ *
+ ****************************************************************************/
+
+#define EEPROM_CS 0x02
+#define EEPROM_SK 0x01
+#define EEPROM_DI 0x04
+#define EEPROM_DO 0x08
+
+static uint16_t eepro100_read_eeprom(EEPRO100State * s)
+{
+ uint16_t val;
+ memcpy(&val, &s->mem[SCBeeprom], sizeof(val));
+ if (eeprom93xx_read(s->eeprom)) {
+ val |= EEPROM_DO;
+ } else {
+ val &= ~EEPROM_DO;
+ }
+ return val;
+}
+
+static void eepro100_write_eeprom(eeprom_t * eeprom, uint8_t val)
+{
+ logout("write val=0x%02x\n", val);
+
+ /* mask unwriteable bits */
+ //~ val = SET_MASKED(val, 0x31, eeprom->value);
+
+ int eecs = ((val & EEPROM_CS) != 0);
+ int eesk = ((val & EEPROM_SK) != 0);
+ int eedi = ((val & EEPROM_DI) != 0);
+ eeprom93xx_write(eeprom, eecs, eesk, eedi);
+}
+
+static void eepro100_write_pointer(EEPRO100State * s, uint32_t val)
+{
+ s->pointer = le32_to_cpu(val);
+ logout("val=0x%08x\n", val);
+}
+
+/*****************************************************************************
+ *
+ * MDI emulation.
+ *
+ ****************************************************************************/
+
+#if defined(DEBUG_EEPRO100)
+static const char *mdi_op_name[] = {
+ "opcode 0",
+ "write",
+ "read",
+ "opcode 3"
+};
+
+static const char *mdi_reg_name[] = {
+ "Control",
+ "Status",
+ "PHY Identification (Word 1)",
+ "PHY Identification (Word 2)",
+ "Auto-Negotiation Advertisement",
+ "Auto-Negotiation Link Partner Ability",
+ "Auto-Negotiation Expansion"
+};
+#endif /* DEBUG_EEPRO100 */
+
+static uint32_t eepro100_read_mdi(EEPRO100State * s)
+{
+ uint32_t val;
+ memcpy(&val, &s->mem[0x10], sizeof(val));
+
+#ifdef DEBUG_EEPRO100
+ uint8_t raiseint = (val & BIT(29)) >> 29;
+ uint8_t opcode = (val & BITS(27, 26)) >> 26;
+ uint8_t phy = (val & BITS(25, 21)) >> 21;
+ uint8_t reg = (val & BITS(20, 16)) >> 16;
+ uint16_t data = (val & BITS(15, 0));
+#endif
+ /* Emulation takes no time to finish MDI transaction. */
+ val |= BIT(28);
+ TRACE(MDI, logout("val=0x%08x (int=%u, %s, phy=%u, %s, data=0x%04x\n",
+ val, raiseint, mdi_op_name[opcode], phy,
+ mdi_reg_name[reg], data));
+ return val;
+}
+
+//~ #define BITS(val, upper, lower) (val & ???)
+static void eepro100_write_mdi(EEPRO100State * s, uint32_t val)
+{
+ uint8_t raiseint = (val & BIT(29)) >> 29;
+ uint8_t opcode = (val & BITS(27, 26)) >> 26;
+ uint8_t phy = (val & BITS(25, 21)) >> 21;
+ uint8_t reg = (val & BITS(20, 16)) >> 16;
+ uint16_t data = (val & BITS(15, 0));
+ if (phy != 1) {
+ /* Unsupported PHY address. */
+ //~ logout("phy must be 1 but is %u\n", phy);
+ data = 0;
+ } else if (opcode != 1 && opcode != 2) {
+ /* Unsupported opcode. */
+ logout("opcode must be 1 or 2 but is %u\n", opcode);
+ data = 0;
+ } else if (reg > 6) {
+ /* Unsupported register. */
+ logout("register must be 0...6 but is %u\n", reg);
+ data = 0;
+ } else {
+ TRACE(MDI, logout("val=0x%08x (int=%u, %s, phy=%u, %s, data=0x%04x\n",
+ val, raiseint, mdi_op_name[opcode], phy,
+ mdi_reg_name[reg], data));
+ if (opcode == 1) {
+ /* MDI write */
+ switch (reg) {
+ case 0: /* Control Register */
+ if (data & 0x8000) {
+ /* Reset status and control registers to default. */
+ s->mdimem[0] = eepro100_mdi_default[0];
+ s->mdimem[1] = eepro100_mdi_default[1];
+ data = s->mdimem[reg];
+ } else {
+ /* Restart Auto Configuration = Normal Operation */
+ data &= ~0x0200;
+ }
+ break;
+ case 1: /* Status Register */
+ missing("not writable");
+ data = s->mdimem[reg];
+ break;
+ case 2: /* PHY Identification Register (Word 1) */
+ case 3: /* PHY Identification Register (Word 2) */
+ missing("not implemented");
+ break;
+ case 4: /* Auto-Negotiation Advertisement Register */
+ case 5: /* Auto-Negotiation Link Partner Ability Register */
+ break;
+ case 6: /* Auto-Negotiation Expansion Register */
+ default:
+ missing("not implemented");
+ }
+ s->mdimem[reg] = data;
+ } else if (opcode == 2) {
+ /* MDI read */
+ switch (reg) {
+ case 0: /* Control Register */
+ if (data & 0x8000) {
+ /* Reset status and control registers to default. */
+ s->mdimem[0] = eepro100_mdi_default[0];
+ s->mdimem[1] = eepro100_mdi_default[1];
+ }
+ break;
+ case 1: /* Status Register */
+ s->mdimem[reg] |= 0x0020;
+ break;
+ case 2: /* PHY Identification Register (Word 1) */
+ case 3: /* PHY Identification Register (Word 2) */
+ case 4: /* Auto-Negotiation Advertisement Register */
+ break;
+ case 5: /* Auto-Negotiation Link Partner Ability Register */
+ s->mdimem[reg] = 0x41fe;
+ break;
+ case 6: /* Auto-Negotiation Expansion Register */
+ s->mdimem[reg] = 0x0001;
+ break;
+ }
+ data = s->mdimem[reg];
+ }
+ /* Emulation takes no time to finish MDI transaction.
+ * Set MDI bit in SCB status register. */
+ s->mem[SCBAck] |= 0x08;
+ val |= BIT(28);
+ if (raiseint) {
+ eepro100_mdi_interrupt(s);
+ }
+ }
+ val = (val & 0xffff0000) + data;
+ memcpy(&s->mem[0x10], &val, sizeof(val));
+}
+
+/*****************************************************************************
+ *
+ * Port emulation.
+ *
+ ****************************************************************************/
+
+#define PORT_SOFTWARE_RESET 0
+#define PORT_SELFTEST 1
+#define PORT_SELECTIVE_RESET 2
+#define PORT_DUMP 3
+#define PORT_SELECTION_MASK 3
+
+typedef struct {
+ uint32_t st_sign; /* Self Test Signature */
+ uint32_t st_result; /* Self Test Results */
+} eepro100_selftest_t;
+
+static uint32_t eepro100_read_port(EEPRO100State * s)
+{
+ return 0;
+}
+
+static void eepro100_write_port(EEPRO100State * s, uint32_t val)
+{
+ val = le32_to_cpu(val);
+ uint32_t address = (val & ~PORT_SELECTION_MASK);
+ uint8_t selection = (val & PORT_SELECTION_MASK);
+ switch (selection) {
+ case PORT_SOFTWARE_RESET:
+ nic_reset(s);
+ break;
+ case PORT_SELFTEST:
+ logout("selftest address=0x%08x\n", address);
+ eepro100_selftest_t data;
+ cpu_physical_memory_read(address, (uint8_t *) & data, sizeof(data));
+ data.st_sign = 0xffffffff;
+ data.st_result = 0;
+ cpu_physical_memory_write(address, (uint8_t *) & data, sizeof(data));
+ break;
+ case PORT_SELECTIVE_RESET:
+ logout("selective reset, selftest address=0x%08x\n", address);
+ nic_selective_reset(s);
+ break;
+ default:
+ logout("val=0x%08x\n", val);
+ missing("unknown port selection");
+ }
+}
+
+/*****************************************************************************
+ *
+ * General hardware emulation.
+ *
+ ****************************************************************************/
+
+static uint8_t eepro100_read1(EEPRO100State * s, uint32_t addr)
+{
+ uint8_t val;
+ if (addr <= sizeof(s->mem) - sizeof(val)) {
+ memcpy(&val, &s->mem[addr], sizeof(val));
+ }
+
+ switch (addr) {
+ case SCBStatus:
+ //~ val = eepro100_read_status(s);
+ logout("addr=%s val=0x%02x\n", regname(addr), val);
+ break;
+ case SCBAck:
+ //~ val = eepro100_read_status(s);
+ logout("addr=%s val=0x%02x\n", regname(addr), val);
+ break;
+ case SCBCmd:
+ logout("addr=%s val=0x%02x\n", regname(addr), val);
+ //~ val = eepro100_read_command(s);
+ break;
+ case SCBIntmask:
+ logout("addr=%s val=0x%02x\n", regname(addr), val);
+ break;
+ case SCBPort + 3:
+ logout("addr=%s val=0x%02x\n", regname(addr), val);
+ break;
+ case SCBeeprom:
+ val = eepro100_read_eeprom(s);
+ break;
+ case 0x1b: /* PMDR (power management driver register) */
+ val = 0;
+ logout("addr=%s val=0x%02x\n", regname(addr), val);
+ break;
+ case 0x1d: /* general status register */
+ /* 100 Mbps full duplex, valid link */
+ val = 0x07;
+ logout("addr=General Status val=%02x\n", val);
+ break;
+ default:
+ logout("addr=%s val=0x%02x\n", regname(addr), val);
+ missing("unknown byte read");
+ }
+ return val;
+}
+
+static uint16_t eepro100_read2(EEPRO100State * s, uint32_t addr)
+{
+ uint16_t val;
+ if (addr <= sizeof(s->mem) - sizeof(val)) {
+ memcpy(&val, &s->mem[addr], sizeof(val));
+ }
+
+ logout("addr=%s val=0x%04x\n", regname(addr), val);
+
+ switch (addr) {
+ case SCBStatus:
+ //~ val = eepro100_read_status(s);
+ break;
+ case SCBeeprom:
+ val = eepro100_read_eeprom(s);
+ break;
+ default:
+ logout("addr=%s val=0x%04x\n", regname(addr), val);
+ missing("unknown word read");
+ }
+ return val;
+}
+
+static uint32_t eepro100_read4(EEPRO100State * s, uint32_t addr)
+{
+ uint32_t val;
+ if (addr <= sizeof(s->mem) - sizeof(val)) {
+ memcpy(&val, &s->mem[addr], sizeof(val));
+ }
+
+ switch (addr) {
+ case SCBStatus:
+ //~ val = eepro100_read_status(s);
+ logout("addr=%s val=0x%08x\n", regname(addr), val);
+ break;
+ case SCBPointer:
+ //~ val = eepro100_read_pointer(s);
+ logout("addr=%s val=0x%08x\n", regname(addr), val);
+ break;
+ case SCBPort:
+ val = eepro100_read_port(s);
+ logout("addr=%s val=0x%08x\n", regname(addr), val);
+ break;
+ case SCBCtrlMDI:
+ val = eepro100_read_mdi(s);
+ break;
+ default:
+ logout("addr=%s val=0x%08x\n", regname(addr), val);
+ missing("unknown longword read");
+ }
+ return val;
+}
+
+static void eepro100_write1(EEPRO100State * s, uint32_t addr, uint8_t val)
+{
+ if (addr <= sizeof(s->mem) - sizeof(val)) {
+ memcpy(&s->mem[addr], &val, sizeof(val));
+ }
+
+ logout("addr=%s val=0x%02x\n", regname(addr), val);
+
+ switch (addr) {
+ case SCBStatus:
+ //~ eepro100_write_status(s, val);
+ break;
+ case SCBAck:
+ eepro100_acknowledge(s);
+ break;
+ case SCBCmd:
+ eepro100_write_command(s, val);
+ break;
+ case SCBIntmask:
+ if (val & BIT(1)) {
+ eepro100_swi_interrupt(s);
+ }
+ eepro100_interrupt(s, 0);
+ break;
+ case SCBPort + 3:
+ logout("addr=%s val=0x%02x\n", regname(addr), val);
+ break;
+ case SCBeeprom:
+ eepro100_write_eeprom(s->eeprom, val);
+ break;
+ default:
+ logout("addr=%s val=0x%02x\n", regname(addr), val);
+ missing("unknown byte write");
+ }
+}
+
+static void eepro100_write2(EEPRO100State * s, uint32_t addr, uint16_t val)
+{
+ if (addr <= sizeof(s->mem) - sizeof(val)) {
+ memcpy(&s->mem[addr], &val, sizeof(val));
+ }
+
+ logout("addr=%s val=0x%04x\n", regname(addr), val);
+
+ switch (addr) {
+ case SCBStatus:
+ //~ eepro100_write_status(s, val);
+ eepro100_acknowledge(s);
+ break;
+ case SCBCmd:
+ eepro100_write_command(s, val);
+ eepro100_write1(s, SCBIntmask, val >> 8);
+ break;
+ case SCBeeprom:
+ eepro100_write_eeprom(s->eeprom, val);
+ break;
+ default:
+ logout("addr=%s val=0x%04x\n", regname(addr), val);
+ missing("unknown word write");
+ }
+}
+
+static void eepro100_write4(EEPRO100State * s, uint32_t addr, uint32_t val)
+{
+ if (addr <= sizeof(s->mem) - sizeof(val)) {
+ memcpy(&s->mem[addr], &val, sizeof(val));
+ }
+
+ switch (addr) {
+ case SCBPointer:
+ eepro100_write_pointer(s, val);
+ break;
+ case SCBPort:
+ logout("addr=%s val=0x%08x\n", regname(addr), val);
+ eepro100_write_port(s, val);
+ break;
+ case SCBCtrlMDI:
+ eepro100_write_mdi(s, val);
+ break;
+ default:
+ logout("addr=%s val=0x%08x\n", regname(addr), val);
+ missing("unknown longword write");
+ }
+}
+
+static uint32_t ioport_read1(void *opaque, uint32_t addr)
+{
+ EEPRO100State *s = opaque;
+ //~ logout("addr=%s\n", regname(addr));
+ return eepro100_read1(s, addr - s->region[1]);
+}
+
+static uint32_t ioport_read2(void *opaque, uint32_t addr)
+{
+ EEPRO100State *s = opaque;
+ return eepro100_read2(s, addr - s->region[1]);
+}
+
+static uint32_t ioport_read4(void *opaque, uint32_t addr)
+{
+ EEPRO100State *s = opaque;
+ return eepro100_read4(s, addr - s->region[1]);
+}
+
+static void ioport_write1(void *opaque, uint32_t addr, uint32_t val)
+{
+ EEPRO100State *s = opaque;
+ //~ logout("addr=%s val=0x%02x\n", regname(addr), val);
+ eepro100_write1(s, addr - s->region[1], val);
+}
+
+static void ioport_write2(void *opaque, uint32_t addr, uint32_t val)
+{
+ EEPRO100State *s = opaque;
+ eepro100_write2(s, addr - s->region[1], val);
+}
+
+static void ioport_write4(void *opaque, uint32_t addr, uint32_t val)
+{
+ EEPRO100State *s = opaque;
+ eepro100_write4(s, addr - s->region[1], val);
+}
+
+/***********************************************************/
+/* PCI EEPRO100 definitions */
+
+typedef struct PCIEEPRO100State {
+ PCIDevice dev;
+ EEPRO100State eepro100;
+} PCIEEPRO100State;
+
+static void pci_map(PCIDevice * pci_dev, int region_num,
+ uint32_t addr, uint32_t size, int type)
+{
+ PCIEEPRO100State *d = (PCIEEPRO100State *) pci_dev;
+ EEPRO100State *s = &d->eepro100;
+
+ logout("region %d, addr=0x%08x, size=0x%08x, type=%d\n",
+ region_num, addr, size, type);
+
+ assert(region_num == 1);
+ register_ioport_write(addr, size, 1, ioport_write1, s);
+ register_ioport_read(addr, size, 1, ioport_read1, s);
+ register_ioport_write(addr, size, 2, ioport_write2, s);
+ register_ioport_read(addr, size, 2, ioport_read2, s);
+ register_ioport_write(addr, size, 4, ioport_write4, s);
+ register_ioport_read(addr, size, 4, ioport_read4, s);
+
+ s->region[region_num] = addr;
+}
+
+static void pci_mmio_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+ EEPRO100State *s = opaque;
+ addr -= s->region[0];
+ //~ logout("addr=%s val=0x%02x\n", regname(addr), val);
+ eepro100_write1(s, addr, val);
+}
+
+static void pci_mmio_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+ EEPRO100State *s = opaque;
+ addr -= s->region[0];
+ //~ logout("addr=%s val=0x%02x\n", regname(addr), val);
+ eepro100_write2(s, addr, val);
+}
+
+static void pci_mmio_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+ EEPRO100State *s = opaque;
+ addr -= s->region[0];
+ //~ logout("addr=%s val=0x%02x\n", regname(addr), val);
+ eepro100_write4(s, addr, val);
+}
+
+static uint32_t pci_mmio_readb(void *opaque, target_phys_addr_t addr)
+{
+ EEPRO100State *s = opaque;
+ addr -= s->region[0];
+ //~ logout("addr=%s\n", regname(addr));
+ return eepro100_read1(s, addr);
+}
+
+static uint32_t pci_mmio_readw(void *opaque, target_phys_addr_t addr)
+{
+ EEPRO100State *s = opaque;
+ addr -= s->region[0];
+ //~ logout("addr=%s\n", regname(addr));
+ return eepro100_read2(s, addr);
+}
+
+static uint32_t pci_mmio_readl(void *opaque, target_phys_addr_t addr)
+{
+ EEPRO100State *s = opaque;
+ addr -= s->region[0];
+ //~ logout("addr=%s\n", regname(addr));
+ return eepro100_read4(s, addr);
+}
+
+static CPUWriteMemoryFunc *pci_mmio_write[] = {
+ pci_mmio_writeb,
+ pci_mmio_writew,
+ pci_mmio_writel
+};
+
+static CPUReadMemoryFunc *pci_mmio_read[] = {
+ pci_mmio_readb,
+ pci_mmio_readw,
+ pci_mmio_readl
+};
+
+static void pci_mmio_map(PCIDevice * pci_dev, int region_num,
+ uint32_t addr, uint32_t size, int type)
+{
+ PCIEEPRO100State *d = (PCIEEPRO100State *) pci_dev;
+
+ logout("region %d, addr=0x%08x, size=0x%08x, type=%d\n",
+ region_num, addr, size, type);
+
+ if (region_num == 0) {
+ /* Map control / status registers. */
+ cpu_register_physical_memory(addr, size, d->eepro100.mmio_index);
+ d->eepro100.region[region_num] = addr;
+ }
+}
+
+static int nic_can_receive(void *opaque)
+{
+ EEPRO100State *s = opaque;
+ logout("%p\n", s);
+ return get_ru_state(s) == ru_ready;
+ //~ return !eepro100_buffer_full(s);
+}
+
+#define MIN_BUF_SIZE 60
+
+static void nic_receive(void *opaque, const uint8_t * buf, int size)
+{
+ /* TODO:
+ * - Magic packets should set bit 30 in power management driver register.
+ * - Interesting packets should set bit 29 in power management driver register.
+ */
+ EEPRO100State *s = opaque;
+ uint16_t rfd_status = 0xa000;
+ static const uint8_t broadcast_macaddr[6] =
+ { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
+
+ /* TODO: check multiple IA bit. */
+ assert(!(s->configuration[20] & BIT(6)));
+
+ if (s->configuration[8] & 0x80) {
+ /* CSMA is disabled. */
+ logout("%p received while CSMA is disabled\n", s);
+ return;
+ } else if (size < 64 && (s->configuration[7] & 1)) {
+ /* Short frame and configuration byte 7/0 (discard short receive) set:
+ * Short frame is discarded */
+ logout("%p received short frame (%d byte)\n", s, size);
+ s->statistics.rx_short_frame_errors++;
+ //~ return;
+ } else if ((size > MAX_ETH_FRAME_SIZE + 4) && !(s->configuration[18] & 8)) {
+ /* Long frame and configuration byte 18/3 (long receive ok) not set:
+ * Long frames are discarded. */
+ logout("%p received long frame (%d byte), ignored\n", s, size);
+ return;
+ } else if (memcmp(buf, s->macaddr, 6) == 0) { // !!!
+ /* Frame matches individual address. */
+ /* TODO: check configuration byte 15/4 (ignore U/L). */
+ logout("%p received frame for me, len=%d\n", s, size);
+ } else if (memcmp(buf, broadcast_macaddr, 6) == 0) {
+ /* Broadcast frame. */
+ logout("%p received broadcast, len=%d\n", s, size);
+ rfd_status |= 0x0002;
+ } else if (buf[0] & 0x01) { // !!!
+ /* Multicast frame. */
+ logout("%p received multicast, len=%d\n", s, size);
+ /* TODO: check multicast all bit. */
+ assert(!(s->configuration[21] & BIT(3)));
+ int mcast_idx = compute_mcast_idx(buf);
+ if (!(s->mult[mcast_idx >> 3] & (1 << (mcast_idx & 7)))) {
+ return;
+ }
+ rfd_status |= 0x0002;
+ } else if (s->configuration[15] & 1) {
+ /* Promiscuous: receive all. */
+ logout("%p received frame in promiscuous mode, len=%d\n", s, size);
+ rfd_status |= 0x0004;
+ } else {
+ logout("%p received frame, ignored, len=%d,%s\n", s, size,
+ nic_dump(buf, size));
+ return;
+ }
+
+ if (get_ru_state(s) != ru_ready) {
+ /* No ressources available. */
+ logout("no ressources, state=%u\n", get_ru_state(s));
+ s->statistics.rx_resource_errors++;
+ //~ assert(!"no ressources");
+ return;
+ }
+ //~ !!!
+//~ $3 = {status = 0x0, command = 0xc000, link = 0x2d220, rx_buf_addr = 0x207dc, count = 0x0, size = 0x5f8, packet = {0x0 <repeats 1518 times>}}
+ eepro100_rx_t rx;
+ cpu_physical_memory_read(s->ru_base + s->ru_offset, (uint8_t *) & rx,
+ offsetof(eepro100_rx_t, packet));
+ uint16_t rfd_command = le16_to_cpu(rx.command);
+ uint16_t rfd_size = le16_to_cpu(rx.size);
+ assert(size <= rfd_size);
+ if (size < 64) {
+ rfd_status |= 0x0080;
+ }
+ logout("command 0x%04x, link 0x%08x, addr 0x%08x, size %u\n", rfd_command,
+ rx.link, rx.rx_buf_addr, rfd_size);
+ stw_phys(s->ru_base + s->ru_offset + offsetof(eepro100_rx_t, status),
+ rfd_status);
+ stw_phys(s->ru_base + s->ru_offset + offsetof(eepro100_rx_t, count), size);
+ /* Early receive interrupt not supported. */
+ //~ eepro100_er_interrupt(s);
+ /* Receive CRC Transfer not supported. */
+ assert(!(s->configuration[18] & 4));
+ /* TODO: check stripping enable bit. */
+ //~ assert(!(s->configuration[17] & 1));
+ cpu_physical_memory_write(s->ru_base + s->ru_offset +
+ offsetof(eepro100_rx_t, packet), buf, size);
+ s->statistics.rx_good_frames++;
+ eepro100_fr_interrupt(s);
+ s->ru_offset = le32_to_cpu(rx.link);
+ if (rfd_command & 0x8000) {
+ /* EL bit is set, so this was the last frame. */
+ assert(0);
+ }
+ if (rfd_command & 0x4000) {
+ /* S bit is set. */
+ set_ru_state(s, ru_suspended);
+ }
+}
+
+static int nic_load(QEMUFile * f, void *opaque, int version_id)
+{
+ EEPRO100State *s = (EEPRO100State *) opaque;
+ int ret;
+
+ missing("NIC load");
+
+ if (version_id > 3)
+ return -EINVAL;
+
+ if (s->pci_dev && version_id >= 3) {
+ ret = pci_device_load(s->pci_dev, f);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (version_id >= 2) {
+ qemu_get_8s(f, &s->rxcr);
+ } else {
+ s->rxcr = 0x0c;
+ }
+
+ qemu_get_8s(f, &s->cmd);
+ qemu_get_be32s(f, &s->start);
+ qemu_get_be32s(f, &s->stop);
+ qemu_get_8s(f, &s->boundary);
+ qemu_get_8s(f, &s->tsr);
+ qemu_get_8s(f, &s->tpsr);
+ qemu_get_be16s(f, &s->tcnt);
+ qemu_get_be16s(f, &s->rcnt);
+ qemu_get_be32s(f, &s->rsar);
+ qemu_get_8s(f, &s->rsr);
+ qemu_get_8s(f, &s->isr);
+ qemu_get_8s(f, &s->dcfg);
+ qemu_get_8s(f, &s->imr);
+ qemu_get_buffer(f, s->phys, 6);
+ qemu_get_8s(f, &s->curpag);
+ qemu_get_buffer(f, s->mult, 8);
+ qemu_get_buffer(f, s->mem, sizeof(s->mem));
+
+ return 0;
+}
+
+static void nic_save(QEMUFile * f, void *opaque)
+{
+ EEPRO100State *s = (EEPRO100State *) opaque;
+
+ missing("NIC save");
+
+ if (s->pci_dev)
+ pci_device_save(s->pci_dev, f);
+
+ qemu_put_8s(f, &s->rxcr);
+
+ qemu_put_8s(f, &s->cmd);
+ qemu_put_be32s(f, &s->start);
+ qemu_put_be32s(f, &s->stop);
+ qemu_put_8s(f, &s->boundary);
+ qemu_put_8s(f, &s->tsr);
+ qemu_put_8s(f, &s->tpsr);
+ qemu_put_be16s(f, &s->tcnt);
+ qemu_put_be16s(f, &s->rcnt);
+ qemu_put_be32s(f, &s->rsar);
+ qemu_put_8s(f, &s->rsr);
+ qemu_put_8s(f, &s->isr);
+ qemu_put_8s(f, &s->dcfg);
+ qemu_put_8s(f, &s->imr);
+ qemu_put_buffer(f, s->phys, 6);
+ qemu_put_8s(f, &s->curpag);
+ qemu_put_buffer(f, s->mult, 8);
+ qemu_put_buffer(f, s->mem, sizeof(s->mem));
+}
+
+static void nic_init(PCIBus * bus, NICInfo * nd,
+ const char *name, uint32_t device)
+{
+ PCIEEPRO100State *d;
+ EEPRO100State *s;
+
+ logout("\n");
+
+ d = (PCIEEPRO100State *) pci_register_device(bus, name,
+ sizeof(PCIEEPRO100State), -1,
+ NULL, NULL);
+
+ s = &d->eepro100;
+ s->device = device;
+ s->pci_dev = &d->dev;
+
+ pci_reset(s);
+
+ /* Add 64 * 2 EEPROM. i82557 and i82558 support a 64 word EEPROM,
+ * i82559 and later support 64 or 256 word EEPROM. */
+ s->eeprom = eeprom93xx_new(EEPROM_SIZE);
+
+ /* Handler for memory-mapped I/O */
+ d->eepro100.mmio_index =
+ cpu_register_io_memory(0, pci_mmio_read, pci_mmio_write, s);
+
+ pci_register_io_region(&d->dev, 0, PCI_MEM_SIZE,
+ PCI_ADDRESS_SPACE_MEM |
+ PCI_ADDRESS_SPACE_MEM_PREFETCH, pci_mmio_map);
+ pci_register_io_region(&d->dev, 1, PCI_IO_SIZE, PCI_ADDRESS_SPACE_IO,
+ pci_map);
+ pci_register_io_region(&d->dev, 2, PCI_FLASH_SIZE, PCI_ADDRESS_SPACE_MEM,
+ pci_mmio_map);
+
+ memcpy(s->macaddr, nd->macaddr, 6);
+ logout("macaddr: %s\n", nic_dump(&s->macaddr[0], 6));
+ assert(s->region[1] == 0);
+
+ nic_reset(s);
+
+ s->vc = qemu_new_vlan_client(nd->vlan, nic_receive, nic_can_receive, s);
+
+ snprintf(s->vc->info_str, sizeof(s->vc->info_str),
+ "eepro100 pci macaddr=%02x:%02x:%02x:%02x:%02x:%02x",
+ s->macaddr[0],
+ s->macaddr[1],
+ s->macaddr[2], s->macaddr[3], s->macaddr[4], s->macaddr[5]);
+
+ qemu_register_reset(nic_reset, s);
+
+ /* XXX: instance number ? */
+ register_savevm(name, 0, 3, nic_save, nic_load, s);
+}
+
+void pci_i82551_init(PCIBus * bus, NICInfo * nd, int devfn)
+{
+ nic_init(bus, nd, "i82551", i82551);
+ //~ uint8_t *pci_conf = d->dev.config;
+}
+
+void pci_i82557b_init(PCIBus * bus, NICInfo * nd, int devfn)
+{
+ nic_init(bus, nd, "i82557b", i82557B);
+}
+
+void pci_i82559er_init(PCIBus * bus, NICInfo * nd, int devfn)
+{
+ nic_init(bus, nd, "i82559er", i82559ER);
+}
+
+/* eof */
Added: trunk/src/host/qemu-neo1973/hw/eeprom93xx.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/eeprom93xx.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/eeprom93xx.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,312 @@
+/*
+ * QEMU EEPROM 93xx emulation
+ *
+ * Copyright (c) 2006-2007 Stefan Weil
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/* Emulation for serial EEPROMs:
+ * NMC93C06 256-Bit (16 x 16)
+ * NMC93C46 1024-Bit (64 x 16)
+ * NMC93C56 2028 Bit (128 x 16)
+ * NMC93C66 4096 Bit (256 x 16)
+ * Compatible devices include FM93C46 and others.
+ *
+ * Other drivers use these interface functions:
+ * eeprom93xx_new - add a new EEPROM (with 16, 64 or 256 words)
+ * eeprom93xx_free - destroy EEPROM
+ * eeprom93xx_read - read data from the EEPROM
+ * eeprom93xx_write - write data to the EEPROM
+ * eeprom93xx_data - get EEPROM data array for external manipulation
+ *
+ * Todo list:
+ * - No emulation of EEPROM timings.
+ */
+
+#include <assert.h>
+#include "eeprom93xx.h"
+
+/* Debug EEPROM emulation. */
+//~ #define DEBUG_EEPROM
+
+#ifdef DEBUG_EEPROM
+#define logout(fmt, args...) fprintf(stderr, "EEPROM\t%-24s" fmt, __func__, ##args)
+#else
+#define logout(fmt, args...) ((void)0)
+#endif
+
+static int eeprom_instance = 0;
+static const int eeprom_version = 20061112;
+
+#if 0
+typedef enum {
+ eeprom_read = 0x80, /* read register xx */
+ eeprom_write = 0x40, /* write register xx */
+ eeprom_erase = 0xc0, /* erase register xx */
+ eeprom_ewen = 0x30, /* erase / write enable */
+ eeprom_ewds = 0x00, /* erase / write disable */
+ eeprom_eral = 0x20, /* erase all registers */
+ eeprom_wral = 0x10, /* write all registers */
+ eeprom_amask = 0x0f,
+ eeprom_imask = 0xf0
+} eeprom_instruction_t;
+#endif
+
+#ifdef DEBUG_EEPROM
+static const char *opstring[] = {
+ "extended", "write", "read", "erase"
+};
+#endif
+
+struct _eeprom_t {
+ uint8_t tick;
+ uint8_t address;
+ uint8_t command;
+ uint8_t writeable;
+
+ uint8_t eecs;
+ uint8_t eesk;
+ uint8_t eedo;
+
+ uint8_t addrbits;
+ uint8_t size;
+ uint16_t data;
+ uint16_t contents[0];
+};
+
+/* Code for saving and restoring of EEPROM state. */
+
+static void eeprom_save(QEMUFile *f, void *opaque)
+{
+ /* Save EEPROM data. */
+ unsigned address;
+ eeprom_t *eeprom = (eeprom_t *)opaque;
+ qemu_put_buffer(f, (uint8_t *)eeprom, sizeof(*eeprom) - 2);
+ qemu_put_be16(f, eeprom->data);
+ for (address = 0; address < eeprom->size; address++) {
+ qemu_put_be16(f, eeprom->contents[address]);
+ }
+}
+
+static int eeprom_load(QEMUFile *f, void *opaque, int version_id)
+{
+ /* Load EEPROM data from saved data if version and EEPROM size
+ of data and current EEPROM are identical. */
+ eeprom_t *eeprom = (eeprom_t *)opaque;
+ int result = -EINVAL;
+ if (version_id == eeprom_version) {
+ unsigned address;
+ uint8_t size = eeprom->size;
+ qemu_get_buffer(f, (uint8_t *)eeprom, sizeof(*eeprom) - 2);
+ if (eeprom->size == size) {
+ eeprom->data = qemu_get_be16(f);
+ for (address = 0; address < eeprom->size; address++) {
+ eeprom->contents[address] = qemu_get_be16(f);
+ }
+ result = 0;
+ }
+ }
+ return result;
+}
+
+void eeprom93xx_write(eeprom_t *eeprom, int eecs, int eesk, int eedi)
+{
+ uint8_t tick = eeprom->tick;
+ uint8_t eedo = eeprom->eedo;
+ uint16_t address = eeprom->address;
+ uint8_t command = eeprom->command;
+
+ logout("CS=%u SK=%u DI=%u DO=%u, tick = %u\n",
+ eecs, eesk, eedi, eedo, tick);
+
+ if (! eeprom->eecs && eecs) {
+ /* Start chip select cycle. */
+ logout("Cycle start, waiting for 1st start bit (0)\n");
+ tick = 0;
+ command = 0x0;
+ address = 0x0;
+ } else if (eeprom->eecs && ! eecs) {
+ /* End chip select cycle. This triggers write / erase. */
+ if (eeprom->writeable) {
+ uint8_t subcommand = address >> (eeprom->addrbits - 2);
+ if (command == 0 && subcommand == 2) {
+ /* Erase all. */
+ for (address = 0; address < eeprom->size; address++) {
+ eeprom->contents[address] = 0xffff;
+ }
+ } else if (command == 3) {
+ /* Erase word. */
+ eeprom->contents[address] = 0xffff;
+ } else if (tick >= 2 + 2 + eeprom->addrbits + 16) {
+ if (command == 1) {
+ /* Write word. */
+ eeprom->contents[address] &= eeprom->data;
+ } else if (command == 0 && subcommand == 1) {
+ /* Write all. */
+ for (address = 0; address < eeprom->size; address++) {
+ eeprom->contents[address] &= eeprom->data;
+ }
+ }
+ }
+ }
+ /* Output DO is tristate, read results in 1. */
+ eedo = 1;
+ } else if (eecs && ! eeprom->eesk && eesk) {
+ /* Raising edge of clock shifts data in. */
+ if (tick == 0) {
+ /* Wait for 1st start bit. */
+ if (eedi == 0) {
+ logout("Got correct 1st start bit, waiting for 2nd start bit (1)\n");
+ tick++;
+ } else {
+ logout("wrong 1st start bit (is 1, should be 0)\n");
+ tick = 2;
+ //~ assert(!"wrong start bit");
+ }
+ } else if (tick == 1) {
+ /* Wait for 2nd start bit. */
+ if (eedi != 0) {
+ logout("Got correct 2nd start bit, getting command + address\n");
+ tick++;
+ } else {
+ logout("1st start bit is longer than needed\n");
+ }
+ } else if (tick < 2 + 2) {
+ /* Got 2 start bits, transfer 2 opcode bits. */
+ tick++;
+ command <<= 1;
+ if (eedi) {
+ command += 1;
+ }
+ } else if (tick < 2 + 2 + eeprom->addrbits) {
+ /* Got 2 start bits and 2 opcode bits, transfer all address bits. */
+ tick++;
+ address = ((address << 1) | eedi);
+ if (tick == 2 + 2 + eeprom->addrbits) {
+ logout("%s command, address = 0x%02x (value 0x%04x)\n",
+ opstring[command], address, eeprom->contents[address]);
+ if (command == 2) {
+ eedo = 0;
+ }
+ address = address % eeprom->size;
+ if (command == 0) {
+ /* Command code in upper 2 bits of address. */
+ switch (address >> (eeprom->addrbits - 2)) {
+ case 0:
+ logout("write disable command\n");
+ eeprom->writeable = 0;
+ break;
+ case 1:
+ logout("write all command\n");
+ break;
+ case 2:
+ logout("erase all command\n");
+ break;
+ case 3:
+ logout("write enable command\n");
+ eeprom->writeable = 1;
+ break;
+ }
+ } else {
+ /* Read, write or erase word. */
+ eeprom->data = eeprom->contents[address];
+ }
+ }
+ } else if (tick < 2 + 2 + eeprom->addrbits + 16) {
+ /* Transfer 16 data bits. */
+ tick++;
+ if (command == 2) {
+ /* Read word. */
+ eedo = ((eeprom->data & 0x8000) != 0);
+ }
+ eeprom->data <<= 1;
+ eeprom->data += eedi;
+ } else {
+ logout("additional unneeded tick, not processed\n");
+ }
+ }
+ /* Save status of EEPROM. */
+ eeprom->tick = tick;
+ eeprom->eecs = eecs;
+ eeprom->eesk = eesk;
+ eeprom->eedo = eedo;
+ eeprom->address = address;
+ eeprom->command = command;
+}
+
+uint16_t eeprom93xx_read(eeprom_t *eeprom)
+{
+ /* Return status of pin DO (0 or 1). */
+ logout("CS=%u DO=%u\n", eeprom->eecs, eeprom->eedo);
+ return (eeprom->eedo);
+}
+
+#if 0
+void eeprom93xx_reset(eeprom_t *eeprom)
+{
+ /* prepare eeprom */
+ logout("eeprom = 0x%p\n", eeprom);
+ eeprom->tick = 0;
+ eeprom->command = 0;
+}
+#endif
+
+eeprom_t *eeprom93xx_new(uint16_t nwords)
+{
+ /* Add a new EEPROM (with 16, 64 or 256 words). */
+ eeprom_t *eeprom;
+ uint8_t addrbits;
+
+ switch (nwords) {
+ case 16:
+ case 64:
+ addrbits = 6;
+ break;
+ case 128:
+ case 256:
+ addrbits = 8;
+ break;
+ default:
+ assert(!"Unsupported EEPROM size, fallback to 64 words!");
+ nwords = 64;
+ addrbits = 6;
+ }
+
+ eeprom = (eeprom_t *)qemu_mallocz(sizeof(*eeprom) + nwords * 2);
+ eeprom->size = nwords;
+ eeprom->addrbits = addrbits;
+ /* Output DO is tristate, read results in 1. */
+ eeprom->eedo = 1;
+ logout("eeprom = 0x%p, nwords = %u\n", eeprom, nwords);
+ register_savevm("eeprom", eeprom_instance, eeprom_version,
+ eeprom_save, eeprom_load, eeprom);
+ return eeprom;
+}
+
+void eeprom93xx_free(eeprom_t *eeprom)
+{
+ /* Destroy EEPROM. */
+ logout("eeprom = 0x%p\n", eeprom);
+ qemu_free(eeprom);
+}
+
+uint16_t *eeprom93xx_data(eeprom_t *eeprom)
+{
+ /* Get EEPROM data array. */
+ return &eeprom->contents[0];
+}
+
+/* eof */
Added: trunk/src/host/qemu-neo1973/hw/eeprom93xx.h
===================================================================
--- trunk/src/host/qemu-neo1973/hw/eeprom93xx.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/eeprom93xx.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,43 @@
+/*
+ * QEMU EEPROM 93xx emulation
+ *
+ * Copyright (c) 2006-2007 Stefan Weil
+ *
+ * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef EEPROM93XX_H
+#define EEPROM93XX_H
+
+#include "vl.h"
+
+typedef struct _eeprom_t eeprom_t;
+
+/* Create a new EEPROM with (nwords * 2) bytes. */
+eeprom_t *eeprom93xx_new(uint16_t nwords);
+
+/* Destroy an existing EEPROM. */
+void eeprom93xx_free(eeprom_t *eeprom);
+
+/* Read from the EEPROM. */
+uint16_t eeprom93xx_read(eeprom_t *eeprom);
+
+/* Write to the EEPROM. */
+void eeprom93xx_write(eeprom_t *eeprom, int eecs, int eesk, int eedi);
+
+/* Get EEPROM data array. */
+uint16_t *eeprom93xx_data(eeprom_t *eeprom);
+
+#endif /* EEPROM93XX_H */
Modified: trunk/src/host/qemu-neo1973/hw/es1370.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/es1370.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/es1370.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -324,7 +324,7 @@
else {
s->status = new_status & ~STAT_INTR;
}
- pci_set_irq (s->pci_dev, 0, !!level);
+ qemu_set_irq(s->pci_dev->irq[0], !!level);
}
static void es1370_reset (ES1370State *s)
@@ -350,7 +350,7 @@
s->dac_voice[i] = NULL;
}
}
- pci_set_irq (s->pci_dev, 0, 0);
+ qemu_irq_lower(s->pci_dev->irq[0]);
}
static void es1370_maybe_lower_irq (ES1370State *s, uint32_t sctl)
Modified: trunk/src/host/qemu-neo1973/hw/esp.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/esp.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/esp.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -507,15 +507,21 @@
qemu_put_be32s(f, &s->ti_rptr);
qemu_put_be32s(f, &s->ti_wptr);
qemu_put_buffer(f, s->ti_buf, TI_BUFSZ);
+ qemu_put_be32s(f, &s->sense);
qemu_put_be32s(f, &s->dma);
+ qemu_put_buffer(f, s->cmdbuf, TI_BUFSZ);
+ qemu_put_be32s(f, &s->cmdlen);
+ qemu_put_be32s(f, &s->do_cmd);
+ qemu_put_be32s(f, &s->dma_left);
+ // There should be no transfers in progress, so dma_counter is not saved
}
static int esp_load(QEMUFile *f, void *opaque, int version_id)
{
ESPState *s = opaque;
- if (version_id != 2)
- return -EINVAL; // Cannot emulate 1
+ if (version_id != 3)
+ return -EINVAL; // Cannot emulate 2
qemu_get_buffer(f, s->rregs, ESP_MAXREG);
qemu_get_buffer(f, s->wregs, ESP_MAXREG);
@@ -523,7 +529,12 @@
qemu_get_be32s(f, &s->ti_rptr);
qemu_get_be32s(f, &s->ti_wptr);
qemu_get_buffer(f, s->ti_buf, TI_BUFSZ);
+ qemu_get_be32s(f, &s->sense);
qemu_get_be32s(f, &s->dma);
+ qemu_get_buffer(f, s->cmdbuf, TI_BUFSZ);
+ qemu_get_be32s(f, &s->cmdlen);
+ qemu_get_be32s(f, &s->do_cmd);
+ qemu_get_be32s(f, &s->dma_left);
return 0;
}
@@ -568,7 +579,7 @@
esp_reset(s);
- register_savevm("esp", espaddr, 2, esp_save, esp_load, s);
+ register_savevm("esp", espaddr, 3, esp_save, esp_load, s);
qemu_register_reset(esp_reset, s);
return s;
Modified: trunk/src/host/qemu-neo1973/hw/fdc.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/fdc.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/fdc.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -1,7 +1,7 @@
/*
* QEMU Floppy disk emulator (Intel 82078)
*
- * Copyright (c) 2003 Jocelyn Mayer
+ * Copyright (c) 2003, 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
@@ -368,7 +368,7 @@
/* Controller's identification */
uint8_t version;
/* HW */
- int irq_lvl;
+ qemu_irq irq;
int dma_chann;
uint32_t io_base;
/* Controller state */
@@ -485,7 +485,100 @@
fdctrl_write_mem,
};
-fdctrl_t *fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped,
+static void fd_save (QEMUFile *f, fdrive_t *fd)
+{
+ uint8_t tmp;
+
+ tmp = fd->drflags;
+ qemu_put_8s(f, &tmp);
+ qemu_put_8s(f, &fd->head);
+ qemu_put_8s(f, &fd->track);
+ qemu_put_8s(f, &fd->sect);
+ qemu_put_8s(f, &fd->dir);
+ qemu_put_8s(f, &fd->rw);
+}
+
+static void fdc_save (QEMUFile *f, void *opaque)
+{
+ fdctrl_t *s = opaque;
+
+ qemu_put_8s(f, &s->state);
+ qemu_put_8s(f, &s->dma_en);
+ qemu_put_8s(f, &s->cur_drv);
+ qemu_put_8s(f, &s->bootsel);
+ qemu_put_buffer(f, s->fifo, FD_SECTOR_LEN);
+ qemu_put_be32s(f, &s->data_pos);
+ qemu_put_be32s(f, &s->data_len);
+ qemu_put_8s(f, &s->data_state);
+ qemu_put_8s(f, &s->data_dir);
+ qemu_put_8s(f, &s->int_status);
+ qemu_put_8s(f, &s->eot);
+ qemu_put_8s(f, &s->timer0);
+ qemu_put_8s(f, &s->timer1);
+ qemu_put_8s(f, &s->precomp_trk);
+ qemu_put_8s(f, &s->config);
+ qemu_put_8s(f, &s->lock);
+ qemu_put_8s(f, &s->pwrd);
+ fd_save(f, &s->drives[0]);
+ fd_save(f, &s->drives[1]);
+}
+
+static int fd_load (QEMUFile *f, fdrive_t *fd)
+{
+ uint8_t tmp;
+
+ qemu_get_8s(f, &tmp);
+ fd->drflags = tmp;
+ qemu_get_8s(f, &fd->head);
+ qemu_get_8s(f, &fd->track);
+ qemu_get_8s(f, &fd->sect);
+ qemu_get_8s(f, &fd->dir);
+ qemu_get_8s(f, &fd->rw);
+
+ return 0;
+}
+
+static int fdc_load (QEMUFile *f, void *opaque, int version_id)
+{
+ fdctrl_t *s = opaque;
+ int ret;
+
+ if (version_id != 1)
+ return -EINVAL;
+
+ qemu_get_8s(f, &s->state);
+ qemu_get_8s(f, &s->dma_en);
+ qemu_get_8s(f, &s->cur_drv);
+ qemu_get_8s(f, &s->bootsel);
+ qemu_get_buffer(f, s->fifo, FD_SECTOR_LEN);
+ qemu_get_be32s(f, &s->data_pos);
+ qemu_get_be32s(f, &s->data_len);
+ qemu_get_8s(f, &s->data_state);
+ qemu_get_8s(f, &s->data_dir);
+ qemu_get_8s(f, &s->int_status);
+ qemu_get_8s(f, &s->eot);
+ qemu_get_8s(f, &s->timer0);
+ qemu_get_8s(f, &s->timer1);
+ qemu_get_8s(f, &s->precomp_trk);
+ qemu_get_8s(f, &s->config);
+ qemu_get_8s(f, &s->lock);
+ qemu_get_8s(f, &s->pwrd);
+
+ ret = fd_load(f, &s->drives[0]);
+ if (ret == 0)
+ ret = fd_load(f, &s->drives[1]);
+
+ return ret;
+}
+
+static void fdctrl_external_reset(void *opaque)
+{
+ fdctrl_t *s = opaque;
+
+ fdctrl_reset(s, 0);
+}
+
+fdctrl_t *fdctrl_init (qemu_irq irq, int dma_chann, int mem_mapped,
uint32_t io_base,
BlockDriverState **fds)
{
@@ -501,7 +594,7 @@
fdctrl_result_timer, fdctrl);
fdctrl->version = 0x90; /* Intel 82078 controller */
- fdctrl->irq_lvl = irq_lvl;
+ fdctrl->irq = irq;
fdctrl->dma_chann = dma_chann;
fdctrl->io_base = io_base;
fdctrl->config = 0x60; /* Implicit seek, polling & FIFO enabled */
@@ -525,6 +618,8 @@
register_ioport_write(io_base + 0x01, 5, 1, &fdctrl_write, fdctrl);
register_ioport_write(io_base + 0x07, 1, 1, &fdctrl_write, fdctrl);
}
+ register_savevm("fdc", io_base, 1, fdc_save, fdc_load, fdctrl);
+ qemu_register_reset(fdctrl_external_reset, fdctrl);
for (i = 0; i < 2; i++) {
fd_revalidate(&fdctrl->drives[i]);
}
@@ -542,7 +637,7 @@
static void fdctrl_reset_irq (fdctrl_t *fdctrl)
{
FLOPPY_DPRINTF("Reset interrupt\n");
- pic_set_irq(fdctrl->irq_lvl, 0);
+ qemu_set_irq(fdctrl->irq, 0);
fdctrl->state &= ~FD_CTRL_INTR;
}
@@ -557,7 +652,7 @@
}
#endif
if (~(fdctrl->state & FD_CTRL_INTR)) {
- pic_set_irq(fdctrl->irq_lvl, 1);
+ qemu_set_irq(fdctrl->irq, 1);
fdctrl->state |= FD_CTRL_INTR;
}
FLOPPY_DPRINTF("Set interrupt status to 0x%02x\n", status);
Modified: trunk/src/host/qemu-neo1973/hw/grackle_pci.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/grackle_pci.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/grackle_pci.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -80,12 +80,12 @@
return (irq_num + (pci_dev->devfn >> 3)) & 3;
}
-static void pci_grackle_set_irq(void *pic, int irq_num, int level)
+static void pci_grackle_set_irq(qemu_irq *pic, int irq_num, int level)
{
- heathrow_pic_set_irq(pic, irq_num + 8, level);
+ qemu_set_irq(pic[irq_num + 8], level);
}
-PCIBus *pci_grackle_init(uint32_t base, void *pic)
+PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic)
{
GrackleState *s;
PCIDevice *d;
Added: trunk/src/host/qemu-neo1973/hw/gt64xxx.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/gt64xxx.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/gt64xxx.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,673 @@
+/*
+ * QEMU GT64120 PCI host
+ *
+ * Copyright (c) 2006,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 "vl.h"
+typedef target_phys_addr_t pci_addr_t;
+#include "pci_host.h"
+
+#define GT_REGS (0x1000 >> 2)
+
+/* CPU Configuration */
+#define GT_CPU (0x000 >> 2)
+#define GT_MULTI (0x120 >> 2)
+
+/* CPU Address Decode */
+#define GT_SCS10LD (0x008 >> 2)
+#define GT_SCS10HD (0x010 >> 2)
+#define GT_SCS32LD (0x018 >> 2)
+#define GT_SCS32HD (0x020 >> 2)
+#define GT_CS20LD (0x028 >> 2)
+#define GT_CS20HD (0x030 >> 2)
+#define GT_CS3BOOTLD (0x038 >> 2)
+#define GT_CS3BOOTHD (0x040 >> 2)
+#define GT_PCI0IOLD (0x048 >> 2)
+#define GT_PCI0IOHD (0x050 >> 2)
+#define GT_PCI0M0LD (0x058 >> 2)
+#define GT_PCI0M0HD (0x060 >> 2)
+#define GT_ISD (0x068 >> 2)
+
+#define GT_PCI0M1LD (0x080 >> 2)
+#define GT_PCI0M1HD (0x088 >> 2)
+#define GT_PCI1IOLD (0x090 >> 2)
+#define GT_PCI1IOHD (0x098 >> 2)
+#define GT_PCI1M0LD (0x0a0 >> 2)
+#define GT_PCI1M0HD (0x0a8 >> 2)
+#define GT_PCI1M1LD (0x0b0 >> 2)
+#define GT_PCI1M1HD (0x0b8 >> 2)
+#define GT_PCI1M1LD (0x0b0 >> 2)
+#define GT_PCI1M1HD (0x0b8 >> 2)
+
+#define GT_SCS10AR (0x0d0 >> 2)
+#define GT_SCS32AR (0x0d8 >> 2)
+#define GT_CS20R (0x0e0 >> 2)
+#define GT_CS3BOOTR (0x0e8 >> 2)
+
+#define GT_PCI0IOREMAP (0x0f0 >> 2)
+#define GT_PCI0M0REMAP (0x0f8 >> 2)
+#define GT_PCI0M1REMAP (0x100 >> 2)
+#define GT_PCI1IOREMAP (0x108 >> 2)
+#define GT_PCI1M0REMAP (0x110 >> 2)
+#define GT_PCI1M1REMAP (0x118 >> 2)
+
+/* CPU Error Report */
+#define GT_CPUERR_ADDRLO (0x070 >> 2)
+#define GT_CPUERR_ADDRHI (0x078 >> 2)
+#define GT_CPUERR_DATALO (0x128 >> 2) /* GT-64120A only */
+#define GT_CPUERR_DATAHI (0x130 >> 2) /* GT-64120A only */
+#define GT_CPUERR_PARITY (0x138 >> 2) /* GT-64120A only */
+
+/* CPU Sync Barrier */
+#define GT_PCI0SYNC (0x0c0 >> 2)
+#define GT_PCI1SYNC (0x0c8 >> 2)
+
+/* SDRAM and Device Address Decode */
+#define GT_SCS0LD (0x400 >> 2)
+#define GT_SCS0HD (0x404 >> 2)
+#define GT_SCS1LD (0x408 >> 2)
+#define GT_SCS1HD (0x40c >> 2)
+#define GT_SCS2LD (0x410 >> 2)
+#define GT_SCS2HD (0x414 >> 2)
+#define GT_SCS3LD (0x418 >> 2)
+#define GT_SCS3HD (0x41c >> 2)
+#define GT_CS0LD (0x420 >> 2)
+#define GT_CS0HD (0x424 >> 2)
+#define GT_CS1LD (0x428 >> 2)
+#define GT_CS1HD (0x42c >> 2)
+#define GT_CS2LD (0x430 >> 2)
+#define GT_CS2HD (0x434 >> 2)
+#define GT_CS3LD (0x438 >> 2)
+#define GT_CS3HD (0x43c >> 2)
+#define GT_BOOTLD (0x440 >> 2)
+#define GT_BOOTHD (0x444 >> 2)
+#define GT_ADERR (0x470 >> 2)
+
+/* SDRAM Configuration */
+#define GT_SDRAM_CFG (0x448 >> 2)
+#define GT_SDRAM_OPMODE (0x474 >> 2)
+#define GT_SDRAM_BM (0x478 >> 2)
+#define GT_SDRAM_ADDRDECODE (0x47c >> 2)
+
+/* SDRAM Parameters */
+#define GT_SDRAM_B0 (0x44c >> 2)
+#define GT_SDRAM_B1 (0x450 >> 2)
+#define GT_SDRAM_B2 (0x454 >> 2)
+#define GT_SDRAM_B3 (0x458 >> 2)
+
+/* Device Parameters */
+#define GT_DEV_B0 (0x45c >> 2)
+#define GT_DEV_B1 (0x460 >> 2)
+#define GT_DEV_B2 (0x464 >> 2)
+#define GT_DEV_B3 (0x468 >> 2)
+#define GT_DEV_BOOT (0x46c >> 2)
+
+/* ECC */
+#define GT_ECC_ERRDATALO (0x480 >> 2) /* GT-64120A only */
+#define GT_ECC_ERRDATAHI (0x484 >> 2) /* GT-64120A only */
+#define GT_ECC_MEM (0x488 >> 2) /* GT-64120A only */
+#define GT_ECC_CALC (0x48c >> 2) /* GT-64120A only */
+#define GT_ECC_ERRADDR (0x490 >> 2) /* GT-64120A only */
+
+/* DMA Record */
+#define GT_DMA0_CNT (0x800 >> 2)
+#define GT_DMA1_CNT (0x804 >> 2)
+#define GT_DMA2_CNT (0x808 >> 2)
+#define GT_DMA3_CNT (0x80c >> 2)
+#define GT_DMA0_SA (0x810 >> 2)
+#define GT_DMA1_SA (0x814 >> 2)
+#define GT_DMA2_SA (0x818 >> 2)
+#define GT_DMA3_SA (0x81c >> 2)
+#define GT_DMA0_DA (0x820 >> 2)
+#define GT_DMA1_DA (0x824 >> 2)
+#define GT_DMA2_DA (0x828 >> 2)
+#define GT_DMA3_DA (0x82c >> 2)
+#define GT_DMA0_NEXT (0x830 >> 2)
+#define GT_DMA1_NEXT (0x834 >> 2)
+#define GT_DMA2_NEXT (0x838 >> 2)
+#define GT_DMA3_NEXT (0x83c >> 2)
+#define GT_DMA0_CUR (0x870 >> 2)
+#define GT_DMA1_CUR (0x874 >> 2)
+#define GT_DMA2_CUR (0x878 >> 2)
+#define GT_DMA3_CUR (0x87c >> 2)
+
+/* DMA Channel Control */
+#define GT_DMA0_CTRL (0x840 >> 2)
+#define GT_DMA1_CTRL (0x844 >> 2)
+#define GT_DMA2_CTRL (0x848 >> 2)
+#define GT_DMA3_CTRL (0x84c >> 2)
+
+/* DMA Arbiter */
+#define GT_DMA_ARB (0x860 >> 2)
+
+/* Timer/Counter */
+#define GT_TC0 (0x850 >> 2)
+#define GT_TC1 (0x854 >> 2)
+#define GT_TC2 (0x858 >> 2)
+#define GT_TC3 (0x85c >> 2)
+#define GT_TC_CONTROL (0x864 >> 2)
+
+/* PCI Internal */
+#define GT_PCI0_CMD (0xc00 >> 2)
+#define GT_PCI0_TOR (0xc04 >> 2)
+#define GT_PCI0_BS_SCS10 (0xc08 >> 2)
+#define GT_PCI0_BS_SCS32 (0xc0c >> 2)
+#define GT_PCI0_BS_CS20 (0xc10 >> 2)
+#define GT_PCI0_BS_CS3BT (0xc14 >> 2)
+#define GT_PCI1_IACK (0xc30 >> 2)
+#define GT_PCI0_IACK (0xc34 >> 2)
+#define GT_PCI0_BARE (0xc3c >> 2)
+#define GT_PCI0_PREFMBR (0xc40 >> 2)
+#define GT_PCI0_SCS10_BAR (0xc48 >> 2)
+#define GT_PCI0_SCS32_BAR (0xc4c >> 2)
+#define GT_PCI0_CS20_BAR (0xc50 >> 2)
+#define GT_PCI0_CS3BT_BAR (0xc54 >> 2)
+#define GT_PCI0_SSCS10_BAR (0xc58 >> 2)
+#define GT_PCI0_SSCS32_BAR (0xc5c >> 2)
+#define GT_PCI0_SCS3BT_BAR (0xc64 >> 2)
+#define GT_PCI1_CMD (0xc80 >> 2)
+#define GT_PCI1_TOR (0xc84 >> 2)
+#define GT_PCI1_BS_SCS10 (0xc88 >> 2)
+#define GT_PCI1_BS_SCS32 (0xc8c >> 2)
+#define GT_PCI1_BS_CS20 (0xc90 >> 2)
+#define GT_PCI1_BS_CS3BT (0xc94 >> 2)
+#define GT_PCI1_BARE (0xcbc >> 2)
+#define GT_PCI1_PREFMBR (0xcc0 >> 2)
+#define GT_PCI1_SCS10_BAR (0xcc8 >> 2)
+#define GT_PCI1_SCS32_BAR (0xccc >> 2)
+#define GT_PCI1_CS20_BAR (0xcd0 >> 2)
+#define GT_PCI1_CS3BT_BAR (0xcd4 >> 2)
+#define GT_PCI1_SSCS10_BAR (0xcd8 >> 2)
+#define GT_PCI1_SSCS32_BAR (0xcdc >> 2)
+#define GT_PCI1_SCS3BT_BAR (0xce4 >> 2)
+#define GT_PCI1_CFGADDR (0xcf0 >> 2)
+#define GT_PCI1_CFGDATA (0xcf4 >> 2)
+#define GT_PCI0_CFGADDR (0xcf8 >> 2)
+#define GT_PCI0_CFGDATA (0xcfc >> 2)
+
+/* Interrupts */
+#define GT_INTRCAUSE (0xc18 >> 2)
+#define GT_INTRMASK (0xc1c >> 2)
+#define GT_PCI0_ICMASK (0xc24 >> 2)
+#define GT_PCI0_SERR0MASK (0xc28 >> 2)
+#define GT_CPU_INTSEL (0xc70 >> 2)
+#define GT_PCI0_INTSEL (0xc74 >> 2)
+#define GT_HINTRCAUSE (0xc98 >> 2)
+#define GT_HINTRMASK (0xc9c >> 2)
+#define GT_PCI0_HICMASK (0xca4 >> 2)
+#define GT_PCI1_SERR1MASK (0xca8 >> 2)
+
+
+typedef PCIHostState GT64120PCIState;
+
+typedef struct GT64120State {
+ GT64120PCIState *pci;
+ uint32_t regs[GT_REGS];
+ target_phys_addr_t PCI0IO_start;
+ target_phys_addr_t PCI0IO_length;
+} GT64120State;
+
+static void gt64120_pci_mapping(GT64120State *s)
+{
+ /* Update IO mapping */
+ if ((s->regs[GT_PCI0IOLD] & 0x7f) <= s->regs[GT_PCI0IOHD])
+ {
+ /* Unmap old IO address */
+ if (s->PCI0IO_length)
+ {
+ cpu_register_physical_memory(s->PCI0IO_start, s->PCI0IO_length, IO_MEM_UNASSIGNED);
+ }
+ /* Map new IO address */
+ s->PCI0IO_start = s->regs[GT_PCI0IOLD] << 21;
+ s->PCI0IO_length = ((s->regs[GT_PCI0IOHD] + 1) - (s->regs[GT_PCI0IOLD] & 0x7f)) << 21;
+ isa_mem_base = s->PCI0IO_start;
+ isa_mmio_init(s->PCI0IO_start, s->PCI0IO_length);
+ }
+}
+
+static void gt64120_writel (void *opaque, target_phys_addr_t addr,
+ uint32_t val)
+{
+ GT64120State *s = opaque;
+ uint32_t saddr;
+
+#ifdef TARGET_WORDS_BIGENDIAN
+ val = bswap32(val);
+#endif
+
+ saddr = (addr & 0xfff) >> 2;
+ switch (saddr) {
+
+ /* CPU Configuration */
+ case GT_CPU:
+ s->regs[GT_CPU] = val;
+ break;
+ case GT_MULTI:
+ /* Read-only register as only one GT64xxx is present on the CPU bus */
+ break;
+
+ /* CPU Address Decode */
+ case GT_PCI0IOLD:
+ s->regs[GT_PCI0IOLD] = val & 0x00007fff;
+ s->regs[GT_PCI0IOREMAP] = val & 0x000007ff;
+ gt64120_pci_mapping(s);
+ break;
+ case GT_PCI0M0LD:
+ s->regs[GT_PCI0M0LD] = val & 0x00007fff;
+ s->regs[GT_PCI0M0REMAP] = val & 0x000007ff;
+ gt64120_pci_mapping(s);
+ break;
+ case GT_PCI0M1LD:
+ s->regs[GT_PCI0M1LD] = val & 0x00007fff;
+ s->regs[GT_PCI0M1REMAP] = val & 0x000007ff;
+ gt64120_pci_mapping(s);
+ break;
+ case GT_PCI1IOLD:
+ s->regs[GT_PCI1IOLD] = val & 0x00007fff;
+ s->regs[GT_PCI1IOREMAP] = val & 0x000007ff;
+ gt64120_pci_mapping(s);
+ break;
+ case GT_PCI1M0LD:
+ s->regs[GT_PCI1M0LD] = val & 0x00007fff;
+ s->regs[GT_PCI1M0REMAP] = val & 0x000007ff;
+ gt64120_pci_mapping(s);
+ break;
+ case GT_PCI1M1LD:
+ s->regs[GT_PCI1M1LD] = val & 0x00007fff;
+ s->regs[GT_PCI1M1REMAP] = val & 0x000007ff;
+ gt64120_pci_mapping(s);
+ break;
+ case GT_PCI0IOHD:
+ case GT_PCI0M0HD:
+ case GT_PCI0M1HD:
+ case GT_PCI1IOHD:
+ case GT_PCI1M0HD:
+ case GT_PCI1M1HD:
+ s->regs[saddr] = val & 0x0000007f;
+ gt64120_pci_mapping(s);
+ break;
+ case GT_PCI0IOREMAP:
+ case GT_PCI0M0REMAP:
+ case GT_PCI0M1REMAP:
+ case GT_PCI1IOREMAP:
+ case GT_PCI1M0REMAP:
+ case GT_PCI1M1REMAP:
+ s->regs[saddr] = val & 0x000007ff;
+ gt64120_pci_mapping(s);
+ break;
+
+ /* CPU Error Report */
+ case GT_CPUERR_ADDRLO:
+ case GT_CPUERR_ADDRHI:
+ case GT_CPUERR_DATALO:
+ case GT_CPUERR_DATAHI:
+ case GT_CPUERR_PARITY:
+ /* Read-only registers, do nothing */
+ break;
+
+ /* CPU Sync Barrier */
+ case GT_PCI0SYNC:
+ case GT_PCI1SYNC:
+ /* Read-only registers, do nothing */
+ break;
+
+ /* ECC */
+ case GT_ECC_ERRDATALO:
+ case GT_ECC_ERRDATAHI:
+ case GT_ECC_MEM:
+ case GT_ECC_CALC:
+ case GT_ECC_ERRADDR:
+ /* Read-only registers, do nothing */
+ break;
+
+ /* PCI Internal */
+ case GT_PCI0_CMD:
+ case GT_PCI1_CMD:
+ s->regs[saddr] = val & 0x0401fc0f;
+ break;
+ case GT_PCI0_CFGADDR:
+ s->pci->config_reg = val & 0x80fffffc;
+ break;
+ case GT_PCI0_CFGDATA:
+ pci_host_data_writel(s->pci, 0, val);
+ break;
+
+ /* SDRAM Parameters */
+ case GT_SDRAM_B0:
+ case GT_SDRAM_B1:
+ case GT_SDRAM_B2:
+ case GT_SDRAM_B3:
+ /* We don't simulate electrical parameters of the SDRAM.
+ Accept, but ignore the values. */
+ s->regs[saddr] = val;
+ break;
+
+ default:
+#if 0
+ printf ("gt64120_writel: Bad register offset 0x%x\n", (int)addr);
+#endif
+ break;
+ }
+}
+
+static uint32_t gt64120_readl (void *opaque,
+ target_phys_addr_t addr)
+{
+ GT64120State *s = opaque;
+ uint32_t val;
+ uint32_t saddr;
+
+ val = 0;
+ saddr = (addr & 0xfff) >> 2;
+
+ switch (saddr) {
+
+ /* CPU Configuration */
+ case GT_MULTI:
+ /* Only one GT64xxx is present on the CPU bus, return
+ the initial value */
+ val = s->regs[saddr];
+ break;
+
+ /* CPU Error Report */
+ case GT_CPUERR_ADDRLO:
+ case GT_CPUERR_ADDRHI:
+ case GT_CPUERR_DATALO:
+ case GT_CPUERR_DATAHI:
+ case GT_CPUERR_PARITY:
+ /* Emulated memory has no error, always return the initial
+ values */
+ val = s->regs[saddr];
+ break;
+
+ /* CPU Sync Barrier */
+ case GT_PCI0SYNC:
+ case GT_PCI1SYNC:
+ /* Reading those register should empty all FIFO on the PCI
+ bus, which are not emulated. The return value should be
+ a random value that should be ignored. */
+ val = 0xc000ffee;
+ break;
+
+ /* ECC */
+ case GT_ECC_ERRDATALO:
+ case GT_ECC_ERRDATAHI:
+ case GT_ECC_MEM:
+ case GT_ECC_CALC:
+ case GT_ECC_ERRADDR:
+ /* Emulated memory has no error, always return the initial
+ values */
+ val = s->regs[saddr];
+ break;
+
+ case GT_CPU:
+ case GT_PCI0IOLD:
+ case GT_PCI0M0LD:
+ case GT_PCI0M1LD:
+ case GT_PCI1IOLD:
+ case GT_PCI1M0LD:
+ case GT_PCI1M1LD:
+ case GT_PCI0IOHD:
+ case GT_PCI0M0HD:
+ case GT_PCI0M1HD:
+ case GT_PCI1IOHD:
+ case GT_PCI1M0HD:
+ case GT_PCI1M1HD:
+ case GT_PCI0_CMD:
+ case GT_PCI1_CMD:
+ case GT_PCI0IOREMAP:
+ case GT_PCI0M0REMAP:
+ case GT_PCI0M1REMAP:
+ case GT_PCI1IOREMAP:
+ case GT_PCI1M0REMAP:
+ case GT_PCI1M1REMAP:
+ val = s->regs[saddr];
+ break;
+ case GT_PCI0_IACK:
+ /* Read the IRQ number */
+ val = pic_read_irq(isa_pic);
+ break;
+
+ /* SDRAM Parameters */
+ case GT_SDRAM_B0:
+ case GT_SDRAM_B1:
+ case GT_SDRAM_B2:
+ case GT_SDRAM_B3:
+ /* We don't simulate electrical parameters of the SDRAM.
+ Just return the last written value. */
+ val = s->regs[saddr];
+ break;
+
+ /* PCI Internal */
+ case GT_PCI0_CFGADDR:
+ val = s->pci->config_reg;
+ break;
+ case GT_PCI0_CFGDATA:
+ val = pci_host_data_readl(s->pci, 0);
+ break;
+
+ default:
+ val = s->regs[saddr];
+#if 0
+ printf ("gt64120_readl: Bad register offset 0x%x\n", (int)addr);
+#endif
+ break;
+ }
+
+#ifdef TARGET_WORDS_BIGENDIAN
+ return bswap32(val);
+#else
+ return val;
+#endif
+}
+
+static CPUWriteMemoryFunc *gt64120_write[] = {
+ >64120_writel,
+ >64120_writel,
+ >64120_writel,
+};
+
+static CPUReadMemoryFunc *gt64120_read[] = {
+ >64120_readl,
+ >64120_readl,
+ >64120_readl,
+};
+
+static int pci_gt64120_map_irq(PCIDevice *pci_dev, int irq_num)
+{
+ int slot;
+
+ slot = (pci_dev->devfn >> 3);
+
+ switch (slot) {
+ /* PIIX4 USB */
+ case 10:
+ return 3;
+ /* AMD 79C973 Ethernet */
+ case 11:
+ return 0;
+ /* Crystal 4281 Sound */
+ case 12:
+ return 0;
+ /* PCI slot 1 to 4 */
+ case 18 ... 21:
+ return ((slot - 18) + irq_num) & 0x03;
+ /* Unknown device, don't do any translation */
+ default:
+ return irq_num;
+ }
+}
+
+extern PCIDevice *piix4_dev;
+static int pci_irq_levels[4];
+
+static void pci_gt64120_set_irq(qemu_irq *pic, int irq_num, int level)
+{
+ int i, pic_irq, pic_level;
+
+ pci_irq_levels[irq_num] = level;
+
+ /* now we change the pic irq level according to the piix irq mappings */
+ /* XXX: optimize */
+ pic_irq = piix4_dev->config[0x60 + irq_num];
+ if (pic_irq < 16) {
+ /* The pic level is the logical OR of all the PCI irqs mapped
+ to it */
+ pic_level = 0;
+ for (i = 0; i < 4; i++) {
+ if (pic_irq == piix4_dev->config[0x60 + i])
+ pic_level |= pci_irq_levels[i];
+ }
+ qemu_set_irq(pic[pic_irq], pic_level);
+ }
+}
+
+
+void gt64120_reset(void *opaque)
+{
+ GT64120State *s = opaque;
+
+ /* CPU Configuration */
+#ifdef TARGET_WORDS_BIGENDIAN
+ s->regs[GT_CPU] = 0x00000000;
+#else
+ s->regs[GT_CPU] = 0x00001000;
+#endif
+ s->regs[GT_MULTI] = 0x00000000;
+
+ /* CPU Address decode FIXME: not complete*/
+ s->regs[GT_PCI0IOLD] = 0x00000080;
+ s->regs[GT_PCI0IOHD] = 0x0000000f;
+ s->regs[GT_PCI0M0LD] = 0x00000090;
+ s->regs[GT_PCI0M0HD] = 0x0000001f;
+ s->regs[GT_PCI0M1LD] = 0x00000790;
+ s->regs[GT_PCI0M1HD] = 0x0000001f;
+ s->regs[GT_PCI1IOLD] = 0x00000100;
+ s->regs[GT_PCI1IOHD] = 0x0000000f;
+ s->regs[GT_PCI1M0LD] = 0x00000110;
+ s->regs[GT_PCI1M0HD] = 0x0000001f;
+ s->regs[GT_PCI1M1LD] = 0x00000120;
+ s->regs[GT_PCI1M1HD] = 0x0000002f;
+ s->regs[GT_PCI0IOREMAP] = 0x00000080;
+ s->regs[GT_PCI0M0REMAP] = 0x00000090;
+ s->regs[GT_PCI0M1REMAP] = 0x00000790;
+ s->regs[GT_PCI1IOREMAP] = 0x00000100;
+ s->regs[GT_PCI1M0REMAP] = 0x00000110;
+ s->regs[GT_PCI1M1REMAP] = 0x00000120;
+
+ /* CPU Error Report */
+ s->regs[GT_CPUERR_ADDRLO] = 0x00000000;
+ s->regs[GT_CPUERR_ADDRHI] = 0x00000000;
+ s->regs[GT_CPUERR_DATALO] = 0xffffffff;
+ s->regs[GT_CPUERR_DATAHI] = 0xffffffff;
+ s->regs[GT_CPUERR_PARITY] = 0x000000ff;
+
+ /* ECC */
+ s->regs[GT_ECC_ERRDATALO] = 0x00000000;
+ s->regs[GT_ECC_ERRDATAHI] = 0x00000000;
+ s->regs[GT_ECC_MEM] = 0x00000000;
+ s->regs[GT_ECC_CALC] = 0x00000000;
+ s->regs[GT_ECC_ERRADDR] = 0x00000000;
+
+ /* SDRAM Parameters */
+ s->regs[GT_SDRAM_B0] = 0x00000005;
+ s->regs[GT_SDRAM_B1] = 0x00000005;
+ s->regs[GT_SDRAM_B2] = 0x00000005;
+ s->regs[GT_SDRAM_B3] = 0x00000005;
+
+ /* PCI Internal FIXME: not complete*/
+#ifdef TARGET_WORDS_BIGENDIAN
+ s->regs[GT_PCI0_CMD] = 0x00000000;
+ s->regs[GT_PCI1_CMD] = 0x00000000;
+#else
+ s->regs[GT_PCI0_CMD] = 0x00010001;
+ s->regs[GT_PCI1_CMD] = 0x00010001;
+#endif
+ s->regs[GT_PCI0_IACK] = 0x00000000;
+ s->regs[GT_PCI1_IACK] = 0x00000000;
+
+ gt64120_pci_mapping(s);
+}
+
+static uint32_t gt64120_read_config(PCIDevice *d, uint32_t address, int len)
+{
+ uint32_t val = pci_default_read_config(d, address, len);
+#ifdef TARGET_WORDS_BIGENDIAN
+ val = bswap32(val);
+#endif
+ return val;
+}
+
+static void gt64120_write_config(PCIDevice *d, uint32_t address, uint32_t val,
+ int len)
+{
+#ifdef TARGET_WORDS_BIGENDIAN
+ val = bswap32(val);
+#endif
+ pci_default_write_config(d, address, val, len);
+}
+
+PCIBus *pci_gt64120_init(qemu_irq *pic)
+{
+ GT64120State *s;
+ PCIDevice *d;
+ int gt64120;
+
+ s = qemu_mallocz(sizeof(GT64120State));
+ s->pci = qemu_mallocz(sizeof(GT64120PCIState));
+ gt64120_reset(s);
+
+ s->pci->bus = pci_register_bus(pci_gt64120_set_irq, pci_gt64120_map_irq,
+ pic, 144, 4);
+
+ gt64120 = cpu_register_io_memory(0, gt64120_read,
+ gt64120_write, s);
+ cpu_register_physical_memory(0x1be00000LL, 0x1000, gt64120);
+
+ d = pci_register_device(s->pci->bus, "GT64120 PCI Bus", sizeof(PCIDevice),
+ 0, gt64120_read_config, gt64120_write_config);
+
+ d->config[0x00] = 0xab; // vendor_id
+ d->config[0x01] = 0x11;
+ d->config[0x02] = 0x20; // device_id
+ d->config[0x03] = 0x46;
+ d->config[0x04] = 0x06;
+ d->config[0x05] = 0x00;
+ d->config[0x06] = 0x80;
+ d->config[0x07] = 0xa2;
+ d->config[0x08] = 0x10;
+ d->config[0x09] = 0x00;
+ d->config[0x0A] = 0x80;
+ d->config[0x0B] = 0x05;
+ d->config[0x0C] = 0x08;
+ d->config[0x0D] = 0x40;
+ d->config[0x0E] = 0x00;
+ d->config[0x0F] = 0x00;
+ d->config[0x17] = 0x08;
+ d->config[0x1B] = 0x1c;
+ d->config[0x1F] = 0x1f;
+ d->config[0x23] = 0x14;
+ d->config[0x27] = 0x14;
+ d->config[0x3D] = 0x01;
+
+ return s->pci->bus;
+}
Modified: trunk/src/host/qemu-neo1973/hw/heathrow_pic.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/heathrow_pic.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/heathrow_pic.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -32,9 +32,9 @@
uint32_t level_triggered;
} HeathrowPIC;
-struct HeathrowPICS {
+typedef struct HeathrowPICS {
HeathrowPIC pics[2];
-};
+} HeathrowPICS;
static inline int check_irq(HeathrowPIC *pic)
{
@@ -130,7 +130,7 @@
};
-void heathrow_pic_set_irq(void *opaque, int num, int level)
+static void heathrow_pic_set_irq(void *opaque, int num, int level)
{
HeathrowPICS *s = opaque;
HeathrowPIC *pic;
@@ -156,7 +156,7 @@
heathrow_pic_update(s);
}
-HeathrowPICS *heathrow_pic_init(int *pmem_index)
+qemu_irq *heathrow_pic_init(int *pmem_index)
{
HeathrowPICS *s;
@@ -164,5 +164,5 @@
s->pics[0].level_triggered = 0;
s->pics[1].level_triggered = 0x1ff00000;
*pmem_index = cpu_register_io_memory(0, pic_read, pic_write, s);
- return s;
+ return qemu_allocate_irqs(heathrow_pic_set_irq, s, 64);
}
Added: trunk/src/host/qemu-neo1973/hw/i2c.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/i2c.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/i2c.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,117 @@
+/*
+ * QEMU I2C bus interface.
+ *
+ * Copyright (c) 2007 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licenced under the LGPL.
+ */
+
+#include "vl.h"
+
+struct i2c_bus
+{
+ i2c_slave *current_dev;
+ i2c_slave *dev;
+};
+
+/* Create a new I2C bus. */
+i2c_bus *i2c_init_bus(void)
+{
+ i2c_bus *bus;
+
+ bus = (i2c_bus *)qemu_mallocz(sizeof(i2c_bus));
+ return bus;
+}
+
+/* Create a new slave device. */
+i2c_slave *i2c_slave_init(i2c_bus *bus, int address, int size)
+{
+ i2c_slave *dev;
+
+ if (size < sizeof(i2c_slave))
+ cpu_abort(cpu_single_env, "I2C struct too small");
+
+ dev = (i2c_slave *)qemu_mallocz(size);
+ dev->address = address;
+ dev->next = bus->dev;
+ bus->dev = dev;
+
+ return dev;
+}
+
+void i2c_set_slave_address(i2c_slave *dev, int address)
+{
+ dev->address = address;
+}
+
+/* Return nonzero if bus is busy. */
+int i2c_bus_busy(i2c_bus *bus)
+{
+ return bus->current_dev != NULL;
+}
+
+/* Returns nonzero if the bus is already busy, or is the address is not
+ valid. */
+/* TODO: Make this handle multiple masters. */
+int i2c_start_transfer(i2c_bus *bus, int address, int recv)
+{
+ i2c_slave *dev;
+
+ for (dev = bus->dev; dev; dev = dev->next) {
+ if (dev->address == address)
+ break;
+ }
+
+ if (!dev)
+ return 1;
+
+ /* If the bus is already busy, assume this is a repeated
+ start condition. */
+ bus->current_dev = dev;
+ dev->event(dev, recv ? I2C_START_RECV : I2C_START_SEND);
+ return 0;
+}
+
+void i2c_end_transfer(i2c_bus *bus)
+{
+ i2c_slave *dev = bus->current_dev;
+
+ if (!dev)
+ return;
+
+ dev->event(dev, I2C_FINISH);
+
+ bus->current_dev = NULL;
+}
+
+int i2c_send(i2c_bus *bus, uint8_t data)
+{
+ i2c_slave *dev = bus->current_dev;
+
+ if (!dev)
+ return -1;
+
+ return dev->send(dev, data);
+}
+
+int i2c_recv(i2c_bus *bus)
+{
+ i2c_slave *dev = bus->current_dev;
+
+ if (!dev)
+ return -1;
+
+ return dev->recv(dev);
+}
+
+void i2c_nack(i2c_bus *bus)
+{
+ i2c_slave *dev = bus->current_dev;
+
+ if (!dev)
+ return;
+
+ dev->event(dev, I2C_NACK);
+}
+
Modified: trunk/src/host/qemu-neo1973/hw/i2c.h
===================================================================
--- trunk/src/host/qemu-neo1973/hw/i2c.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/i2c.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -1,187 +1,80 @@
-/*
- * Simplified I2C(tm) bus / SMBus(tm).
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Written by Andrzej Zaborowski <balrog at zabor.org>
- *
- * This file is licensed under GNU GPL.
- */
+#ifndef QEMU_I2C_H
+#define QEMU_I2C_H
-#define I2C_MAX_MSG 4096
+/* The QEMU I2C implementation only supports simple transfers that complete
+ immediately. It does not support slave devices that need to be able to
+ defer their response (eg. CPU slave interfaces where the data is supplied
+ by the device driver in response to an interrupt). */
-struct i2c_slave_s {
- uint8_t address;
- int (*tx)(void *opaque, uint8_t *data, int len);
- void (*start)(void *opaque, int dir);
- void (*stop)(void *opaque);
- void *opaque;
+enum i2c_event {
+ I2C_START_RECV,
+ I2C_START_SEND,
+ I2C_FINISH,
+ I2C_NACK /* Masker NACKed a recieve byte. */
};
-struct i2c_bus_s {
- struct i2c_slave_s *slave[0x80];
- uint8_t current;
- int dir;
-};
+typedef struct i2c_slave i2c_slave;
-/* I2C master - drives the clock signal on a bus. There can be multiple
- * masters on one bus. */
-struct i2c_master_s {
- struct i2c_bus_s *bus;
- uint8_t message[I2C_MAX_MSG];
- int message_len;
- int ack;
+/* Master to slave. */
+typedef int (*i2c_send_cb)(i2c_slave *s, uint8_t data);
+/* Slave to master. */
+typedef int (*i2c_recv_cb)(i2c_slave *s);
+/* Notify the slave of a bus state change. */
+typedef void (*i2c_event_cb)(i2c_slave *s, enum i2c_event event);
- uint8_t data;
-};
-
-static inline int i2c_bus_start(struct i2c_bus_s *bus, uint8_t byte)
+struct i2c_slave
{
- struct i2c_slave_s *slave;
+ /* Callbacks to be set by the device. */
+ i2c_event_cb event;
+ i2c_recv_cb recv;
+ i2c_send_cb send;
- bus->current = byte >> 1;
- bus->dir = byte & 1;
- slave = bus->slave[bus->current];
+ /* Remaining fields for internal use by the I2C code. */
+ int address;
+ void *next;
+};
- return !slave;
-}
+typedef struct i2c_bus i2c_bus;
-static inline int i2c_start_submit(struct i2c_bus_s *bus)
-{
- struct i2c_slave_s *slave = bus->slave[bus->current];
- if (!slave)
- return 1;
+i2c_bus *i2c_init_bus(void);
+i2c_slave *i2c_slave_init(i2c_bus *bus, int address, int size);
+void i2c_set_slave_address(i2c_slave *dev, int address);
+int i2c_bus_busy(i2c_bus *bus);
+int i2c_start_transfer(i2c_bus *bus, int address, int recv);
+void i2c_end_transfer(i2c_bus *bus);
+void i2c_nack(i2c_bus *bus);
+int i2c_send(i2c_bus *bus, uint8_t data);
+int i2c_recv(i2c_bus *bus);
- if (slave->start)
- slave->start(slave->opaque, bus->dir);
- return 0;
-}
-
-static inline int i2c_stop_submit(struct i2c_bus_s *bus)
-{
- struct i2c_slave_s *slave = bus->slave[bus->current];
- if (!slave)
- return 1;
-
- if (slave->stop)
- slave->stop(slave->opaque);
- return 0;
-}
-
-static inline int i2c_msg_submit(struct i2c_bus_s *bus,
- uint8_t message[], int len)
-{
- struct i2c_slave_s *slave = bus->slave[bus->current];
- if (!slave)
- return 1;
-
- return slave->tx ? slave->tx(slave->opaque, message, len) : 1;
-}
-
-static inline void i2c_master_submit(struct i2c_master_s *master,
- int start, int stop)
-{
- int ret = 0;
-
- if (!master->bus) {
- master->ack = 0;
- return;
- }
-
- if (start) {
- if (master->message_len)
- if (!master->bus->dir) { /* Master --> Slave */
- i2c_start_submit(master->bus);
- ret = i2c_msg_submit(master->bus,
- master->message, master->message_len);
- master->message_len = 0;
- }
-
- ret = i2c_bus_start(master->bus, master->data);
- master->message_len = 0;
-
- if (master->bus->dir) { /* Master <-- Slave */
- i2c_start_submit(master->bus);
- master->message_len = 1;
- if (stop)
- i2c_msg_submit(master->bus, master->message, 0);
- }
- } else if (stop < 2) {
- if (!master->bus->dir) { /* Master --> Slave */
- if (master->message_len < I2C_MAX_MSG)
- master->message[master->message_len ++] = master->data;
- } else { /* Master <-- Slave */
- ret = i2c_msg_submit(master->bus,
- master->message, master->message_len);
- master->data = master->message[0];
- }
- }
-
- if (stop) {
- if (!master->bus->dir) { /* Master --> Slave */
- i2c_start_submit(master->bus);
- ret = i2c_msg_submit(master->bus,
- master->message, master->message_len);
- master->message_len = 0;
- }
-
- i2c_stop_submit(master->bus);
- }
-
- master->ack = !ret;
-}
-
-/* Call with zero `addr' to detach. */
-static inline void i2c_slave_attach(struct i2c_bus_s *bus, uint8_t addr,
- struct i2c_slave_s *dev)
-{
- if (addr >= 0x80)
- cpu_abort(cpu_single_env, "bad I2C address");
-
- if (dev->address)
- bus->slave[dev->address] = 0;
-
- dev->address = addr;
-
- if (dev->address)
- bus->slave[dev->address] = dev;
-}
-
-static inline void i2c_master_attach(struct i2c_bus_s *bus,
- struct i2c_master_s *dev)
-{
- dev->bus = bus;
-}
-
/* max7310.c */
-struct i2c_slave_s *max7310_init(void);
-void max7310_reset(struct i2c_slave_s *i2c);
-void max7310_gpio_set(struct i2c_slave_s *i2c, int line, int level);
-void max7310_gpio_handler_set(struct i2c_slave_s *i2c, int line,
+i2c_slave *max7310_init(i2c_bus *bus);
+void max7310_reset(i2c_slave *i2c);
+void max7310_gpio_set(i2c_slave *i2c, int line, int level);
+void max7310_gpio_handler_set(i2c_slave *i2c, int line,
gpio_handler_t handler, void *opaque);
/* wm8750.c */
-struct i2c_slave_s *wm8750_init(AudioState *audio);
-void wm8750_reset(struct i2c_slave_s *i2c);
-void wm8750_data_req_set(struct i2c_slave_s *i2c,
+i2c_slave *wm8750_init(i2c_bus *bus, AudioState *audio);
+void wm8750_reset(i2c_slave *i2c);
+void wm8750_data_req_set(i2c_slave *i2c,
void (*data_req)(void *, int, int), void *opaque);
void wm8750_dac_dat(void *opaque, uint32_t sample);
uint32_t wm8750_adc_dat(void *opaque);
/* wm8753.c */
-struct i2c_slave_s *wm8753_init(AudioState *audio);
-void wm8753_reset(struct i2c_slave_s *i2c);
-void wm8753_data_req_set(struct i2c_slave_s *i2c,
+i2c_slave *wm8753_init(i2c_bus *bus, AudioState *audio);
+void wm8753_reset(i2c_slave *i2c);
+void wm8753_data_req_set(i2c_slave *i2c,
void (*data_req)(void *, int, int), void *opaque);
void wm8753_dac_dat(void *opaque, uint32_t sample);
uint32_t wm8753_adc_dat(void *opaque);
-void wm8753_gpio_set(struct i2c_slave_s *i2c, int line, int level);
-void wm8753_gpio_handler_set(struct i2c_slave_s *i2c, int line,
- gpio_handler_t handler, void *opaque);
+qemu_irq *wm8753_gpio_in_get(i2c_slave *i2c);
+void wm8753_gpio_out_set(i2c_slave *i2c, int line, qemu_irq handler);
/* pcf5060x.c */
-struct i2c_slave_s *pcf5060x_init(void *pic, int irq, int tsc);
-void pcf_reset(struct i2c_slave_s *i2c);
-void pcf_gpo_handler_set(struct i2c_slave_s *i2c, int line,
- gpio_handler_t handler, void *opaque);
-void pcf_onkey_set(struct i2c_slave_s *i2c, int level);
-void pcf_exton_set(struct i2c_slave_s *i2c, int level);
+i2c_slave *pcf5060x_init(i2c_bus *bus, qemu_irq irq, int tsc);
+void pcf_reset(i2c_slave *i2c);
+void pcf_gpo_handler_set(i2c_slave *i2c, int line, qemu_irq handler);
+void pcf_onkey_set(i2c_slave *i2c, int level);
+void pcf_exton_set(i2c_slave *i2c, int level);
+#endif
Modified: trunk/src/host/qemu-neo1973/hw/i8254.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/i8254.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/i8254.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -47,7 +47,7 @@
/* irq handling */
int64_t next_transition_time;
QEMUTimer *irq_timer;
- int irq;
+ qemu_irq irq;
} PITChannelState;
struct PITState {
@@ -366,7 +366,7 @@
return;
expire_time = pit_get_next_transition_time(s, current_time);
irq_level = pit_get_out1(s, current_time);
- pic_set_irq(s->irq, irq_level);
+ qemu_set_irq(s->irq, irq_level);
#ifdef DEBUG_PIT
printf("irq_level=%d next_delay=%f\n",
irq_level,
@@ -460,7 +460,7 @@
}
}
-PITState *pit_init(int base, int irq)
+PITState *pit_init(int base, qemu_irq irq)
{
PITState *pit = &pit_state;
PITChannelState *s;
Modified: trunk/src/host/qemu-neo1973/hw/i8259.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/i8259.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/i8259.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -44,6 +44,7 @@
uint8_t rotate_on_auto_eoi;
uint8_t special_fully_nested_mode;
uint8_t init4; /* true if 4 byte init */
+ uint8_t single_mode; /* true if slave pic is not initialized */
uint8_t elcr; /* PIIX edge/trigger selection*/
uint8_t elcr_mask;
PicState2 *pics_state;
@@ -53,7 +54,7 @@
/* 0 is master pic, 1 is slave pic */
/* XXX: better separation between the two pics */
PicState pics[2];
- IRQRequestFunc *irq_request;
+ qemu_irq parent_irq;
void *irq_request_opaque;
/* IOAPIC callback support */
SetIRQFunc *alt_irq_func;
@@ -159,22 +160,29 @@
}
printf("pic: cpu_interrupt\n");
#endif
- s->irq_request(s->irq_request_opaque, 1);
+ qemu_irq_raise(s->parent_irq);
}
+
+/* all targets should do this rather than acking the IRQ in the cpu */
+#if defined(TARGET_MIPS)
+ else {
+ qemu_irq_lower(s->parent_irq);
+ }
+#endif
}
#ifdef DEBUG_IRQ_LATENCY
int64_t irq_time[16];
#endif
-void pic_set_irq_new(void *opaque, int irq, int level)
+void i8259_set_irq(void *opaque, int irq, int level)
{
PicState2 *s = opaque;
#if defined(DEBUG_PIC) || defined(DEBUG_IRQ_COUNT)
if (level != irq_level[irq]) {
#if defined(DEBUG_PIC)
- printf("pic_set_irq: irq=%d level=%d\n", irq, level);
+ printf("i8259_set_irq: irq=%d level=%d\n", irq, level);
#endif
irq_level[irq] = level;
#ifdef DEBUG_IRQ_COUNT
@@ -195,12 +203,6 @@
pic_update_irq(s);
}
-/* obsolete function */
-void pic_set_irq(int irq, int level)
-{
- pic_set_irq_new(isa_pic, irq, level);
-}
-
/* acknowledge interrupt 'irq' */
static inline void pic_intack(PicState *s, int irq)
{
@@ -271,6 +273,7 @@
s->rotate_on_auto_eoi = 0;
s->special_fully_nested_mode = 0;
s->init4 = 0;
+ s->single_mode = 0;
/* Note: ELCR is not reset */
}
@@ -288,11 +291,10 @@
/* init */
pic_reset(s);
/* deassert a pending interrupt */
- s->pics_state->irq_request(s->pics_state->irq_request_opaque, 0);
+ qemu_irq_lower(s->pics_state->parent_irq);
s->init_state = 1;
s->init4 = val & 1;
- if (val & 0x02)
- hw_error("single mode not supported");
+ s->single_mode = val & 2;
if (val & 0x08)
hw_error("level sensitive irq not supported");
} else if (val & 0x08) {
@@ -349,7 +351,7 @@
break;
case 1:
s->irq_base = val & 0xf8;
- s->init_state = 2;
+ s->init_state = s->single_mode && s->init4 ? 3 : 2;
break;
case 2:
if (s->init4) {
@@ -461,6 +463,7 @@
qemu_put_8s(f, &s->rotate_on_auto_eoi);
qemu_put_8s(f, &s->special_fully_nested_mode);
qemu_put_8s(f, &s->init4);
+ qemu_put_8s(f, &s->single_mode);
qemu_put_8s(f, &s->elcr);
}
@@ -485,6 +488,7 @@
qemu_get_8s(f, &s->rotate_on_auto_eoi);
qemu_get_8s(f, &s->special_fully_nested_mode);
qemu_get_8s(f, &s->init4);
+ qemu_get_8s(f, &s->single_mode);
qemu_get_8s(f, &s->elcr);
return 0;
}
@@ -536,9 +540,10 @@
#endif
}
-PicState2 *pic_init(IRQRequestFunc *irq_request, void *irq_request_opaque)
+qemu_irq *i8259_init(qemu_irq parent_irq)
{
PicState2 *s;
+
s = qemu_mallocz(sizeof(PicState2));
if (!s)
return NULL;
@@ -546,11 +551,11 @@
pic_init1(0xa0, 0x4d1, &s->pics[1]);
s->pics[0].elcr_mask = 0xf8;
s->pics[1].elcr_mask = 0xde;
- s->irq_request = irq_request;
- s->irq_request_opaque = irq_request_opaque;
+ s->parent_irq = parent_irq;
s->pics[0].pics_state = s;
s->pics[1].pics_state = s;
- return s;
+ isa_pic = s;
+ return qemu_allocate_irqs(i8259_set_irq, s, 16);
}
void pic_set_alt_irq_func(PicState2 *s, SetIRQFunc *alt_irq_func,
Modified: trunk/src/host/qemu-neo1973/hw/ide.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/ide.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/ide.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -2,6 +2,7 @@
* QEMU IDE disk and CD-ROM Emulator
*
* Copyright (c) 2003 Fabrice Bellard
+ * Copyright (c) 2006 Openedhand Ltd.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -311,9 +312,7 @@
int mult_sectors;
int identify_set;
uint16_t identify_data[256];
- SetIRQFunc *set_irq;
- void *irq_opaque;
- int irq;
+ qemu_irq irq;
PCIDevice *pci_dev;
struct BMDMAState *bmdma;
int drive_serial;
@@ -411,6 +410,7 @@
} PCIIDEState;
static void ide_dma_start(IDEState *s, BlockDriverCompletionFunc *dma_cb);
+static void ide_atapi_cmd_read_dma_cb(void *opaque, int ret);
static void padstr(char *str, const char *src, int len)
{
@@ -659,7 +659,7 @@
if (bm) {
bm->status |= BM_STATUS_INT;
}
- s->set_irq(s->irq_opaque, s->irq, 1);
+ qemu_irq_raise(s->irq);
}
}
@@ -878,7 +878,7 @@
ret = bdrv_write(s->bs, sector_num, s->io_buffer, n);
s->nsector -= n;
if (s->nsector == 0) {
- /* no more sector to write */
+ /* no more sectors to write */
ide_transfer_stop(s);
} else {
n1 = s->nsector;
@@ -1148,11 +1148,17 @@
size = max_size;
s->lba = -1; /* no sector read */
s->packet_transfer_size = size;
+ s->io_buffer_size = size; /* dma: send the reply data as one chunk */
s->elementary_transfer_size = 0;
s->io_buffer_index = 0;
- s->status = READY_STAT;
- ide_atapi_cmd_reply_end(s);
+ if (s->atapi_dma) {
+ s->status = READY_STAT | DRQ_STAT;
+ ide_dma_start(s, ide_atapi_cmd_read_dma_cb);
+ } else {
+ s->status = READY_STAT;
+ ide_atapi_cmd_reply_end(s);
+ }
}
/* start a CD-CDROM read command */
@@ -1184,14 +1190,23 @@
}
if (s->io_buffer_size > 0) {
- if (s->cd_sector_size == 2352) {
- n = 1;
- cd_data_to_raw(s->io_buffer, s->lba);
- } else {
- n = s->io_buffer_size >> 11;
- }
+ /*
+ * For a cdrom read sector command (s->lba != -1),
+ * adjust the lba for the next s->io_buffer_size chunk
+ * and dma the current chunk.
+ * For a command != read (s->lba == -1), just transfer
+ * the reply data.
+ */
+ if (s->lba != -1) {
+ if (s->cd_sector_size == 2352) {
+ n = 1;
+ cd_data_to_raw(s->io_buffer, s->lba);
+ } else {
+ n = s->io_buffer_size >> 11;
+ }
+ s->lba += n;
+ }
s->packet_transfer_size -= s->io_buffer_size;
- s->lba += n;
if (dma_buf_rw(bm, 1) == 0)
goto eot;
}
@@ -1255,7 +1270,8 @@
int sector_size)
{
#ifdef DEBUG_IDE_ATAPI
- printf("read: LBA=%d nb_sectors=%d\n", lba, nb_sectors);
+ printf("read %s: LBA=%d nb_sectors=%d\n", s->atapi_dma ? "dma" : "pio",
+ lba, nb_sectors);
#endif
if (s->atapi_dma) {
ide_atapi_cmd_read_dma(s, lba, nb_sectors, sector_size);
@@ -1759,12 +1775,12 @@
/* Disable Read and Write Multiple */
s->mult_sectors = 0;
s->status = READY_STAT;
- } else if (s->nsector > MAX_MULT_SECTORS ||
- s->nsector == 0 ||
- (s->nsector & (s->nsector - 1)) != 0) {
+ } else if ((s->nsector & 0xff) != 0 &&
+ ((s->nsector & 0xff) > MAX_MULT_SECTORS ||
+ (s->nsector & (s->nsector - 1)) != 0)) {
ide_abort_command(s);
} else {
- s->mult_sectors = s->nsector;
+ s->mult_sectors = s->nsector & 0xff;
s->status = READY_STAT;
}
ide_set_irq(s);
@@ -1864,6 +1880,8 @@
goto abort_cmd;
/* XXX: valid for CDROM ? */
switch(s->feature) {
+ case 0xcc: /* reverting to power-on defaults enable */
+ case 0x66: /* reverting to power-on defaults disable */
case 0x02: /* write cache enable */
case 0x82: /* write cache disable */
case 0xaa: /* read look-ahead enable */
@@ -1874,8 +1892,6 @@
case 0x67: /* NOP */
case 0x96: /* NOP */
case 0x9a: /* NOP */
- case 0x66: /* disable power on reset at soft reset */
- case 0xcc: /* enable power on reset at soft reset */
s->status = READY_STAT | SEEK_STAT;
ide_set_irq(s);
break;
@@ -1915,7 +1931,7 @@
ide_set_irq(s);
break;
case WIN_STANDBYNOW1:
- case WIN_STANDBYNOW2:
+ case WIN_STANDBYNOW2:
case WIN_IDLEIMMEDIATE:
case CFA_IDLEIMMEDIATE:
case WIN_SETIDLE1:
@@ -2107,7 +2123,7 @@
ret = 0;
else
ret = s->status;
- s->set_irq(s->irq_opaque, s->irq, 0);
+ qemu_irq_lower(s->irq);
break;
}
#ifdef DEBUG_IDE
@@ -2306,7 +2322,7 @@
static void ide_init2(IDEState *ide_state,
BlockDriverState *hd0, BlockDriverState *hd1,
- SetIRQFunc *set_irq, void *irq_opaque, int irq)
+ qemu_irq irq)
{
IDEState *s;
static int drive_serial = 1;
@@ -2377,8 +2393,6 @@
}
}
s->drive_serial = drive_serial++;
- s->set_irq = set_irq;
- s->irq_opaque = irq_opaque;
s->irq = irq;
s->sector_write_timer = qemu_new_timer(vm_clock,
ide_sector_write_timer_cb, s);
@@ -2405,7 +2419,7 @@
/***********************************************************/
/* ISA IDE definitions */
-void isa_ide_init(int iobase, int iobase2, int irq,
+void isa_ide_init(int iobase, int iobase2, qemu_irq irq,
BlockDriverState *hd0, BlockDriverState *hd1)
{
IDEState *ide_state;
@@ -2414,7 +2428,7 @@
if (!ide_state)
return;
- ide_init2(ide_state, hd0, hd1, pic_set_irq_new, isa_pic, irq);
+ ide_init2(ide_state, hd0, hd1, irq);
ide_init_ioport(ide_state, iobase, iobase2);
}
@@ -2454,7 +2468,6 @@
return;
bm->ide_if = s;
bm->dma_cb = dma_cb;
- bm->cur_addr = bm->addr;
bm->cur_prd_last = 0;
bm->cur_prd_addr = 0;
bm->cur_prd_len = 0;
@@ -2587,6 +2600,7 @@
printf("%s: 0x%08x\n", __func__, val);
#endif
bm->addr = val & ~3;
+ bm->cur_addr = bm->addr;
}
static void bmdma_map(PCIDevice *pci_dev, int region_num,
@@ -2621,7 +2635,7 @@
!(d->dev.config[MRDMODE] & MRDMODE_BLK_CH0)) ||
((d->dev.config[MRDMODE] & MRDMODE_INTR_CH1) &&
!(d->dev.config[MRDMODE] & MRDMODE_BLK_CH1));
- pci_set_irq((PCIDevice *)d, 0, pci_level);
+ qemu_set_irq(d->dev.irq[0], pci_level);
}
/* the PCI irq level is the logical OR of the two channels */
@@ -2645,6 +2659,7 @@
PCIIDEState *d;
uint8_t *pci_conf;
int i;
+ qemu_irq *irq;
d = (PCIIDEState *)pci_register_device(bus, "CMD646 IDE",
sizeof(PCIIDEState),
@@ -2684,10 +2699,10 @@
for(i = 0; i < 4; i++)
d->ide_if[i].pci_dev = (PCIDevice *)d;
- ide_init2(&d->ide_if[0], hd_table[0], hd_table[1],
- cmd646_set_irq, d, 0);
- ide_init2(&d->ide_if[2], hd_table[2], hd_table[3],
- cmd646_set_irq, d, 1);
+
+ irq = qemu_allocate_irqs(cmd646_set_irq, d, 2);
+ ide_init2(&d->ide_if[0], hd_table[0], hd_table[1], irq[0]);
+ ide_init2(&d->ide_if[2], hd_table[2], hd_table[3], irq[1]);
}
static void pci_ide_save(QEMUFile* f, void *opaque)
@@ -2801,9 +2816,21 @@
return 0;
}
+static void piix3_reset(PCIIDEState *d)
+{
+ uint8_t *pci_conf = d->dev.config;
+
+ pci_conf[0x04] = 0x00;
+ pci_conf[0x05] = 0x00;
+ pci_conf[0x06] = 0x80; /* FBC */
+ pci_conf[0x07] = 0x02; // PCI_status_devsel_medium
+ pci_conf[0x20] = 0x01; /* BMIBA: 20-23h */
+}
+
/* hd_table must contain 4 block drivers */
/* NOTE: for the PIIX3, the IRQs and IOports are hardcoded */
-void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn)
+void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn,
+ qemu_irq *pic)
{
PCIIDEState *d;
uint8_t *pci_conf;
@@ -2825,13 +2852,13 @@
pci_conf[0x0b] = 0x01; // class_base = PCI_mass_storage
pci_conf[0x0e] = 0x00; // header_type
+ piix3_reset(d);
+
pci_register_io_region((PCIDevice *)d, 4, 0x10,
PCI_ADDRESS_SPACE_IO, bmdma_map);
- ide_init2(&d->ide_if[0], hd_table[0], hd_table[1],
- pic_set_irq_new, isa_pic, 14);
- ide_init2(&d->ide_if[2], hd_table[2], hd_table[3],
- pic_set_irq_new, isa_pic, 15);
+ ide_init2(&d->ide_if[0], hd_table[0], hd_table[1], pic[14]);
+ ide_init2(&d->ide_if[2], hd_table[2], hd_table[3], pic[15]);
ide_init_ioport(&d->ide_if[0], 0x1f0, 0x3f6);
ide_init_ioport(&d->ide_if[2], 0x170, 0x376);
@@ -2950,15 +2977,13 @@
/* hd_table must contain 4 block drivers */
/* PowerMac uses memory mapped registers, not I/O. Return the memory
I/O index to access the ide. */
-int pmac_ide_init (BlockDriverState **hd_table,
- SetIRQFunc *set_irq, void *irq_opaque, int irq)
+int pmac_ide_init (BlockDriverState **hd_table, qemu_irq irq)
{
IDEState *ide_if;
int pmac_ide_memory;
ide_if = qemu_mallocz(sizeof(IDEState) * 2);
- ide_init2(&ide_if[0], hd_table[0], hd_table[1],
- set_irq, irq_opaque, irq);
+ ide_init2(&ide_if[0], hd_table[0], hd_table[1], irq);
pmac_ide_memory = cpu_register_io_memory(0, pmac_ide_read,
pmac_ide_write, &ide_if[0]);
@@ -2968,4 +2993,492 @@
/***********************************************************/
/* CF-ATA Microdrive */
-#include "md.c"
+#define METADATA_SIZE 0x20
+
+/* DSCM-1XXXX Microdrive hard disk with CF+ II / PCMCIA interface. */
+struct md_s {
+ IDEState ide[2];
+ struct pcmcia_card_s card;
+ uint32_t attr_base;
+ uint32_t io_base;
+
+ /* Card state */
+ uint8_t opt;
+ uint8_t stat;
+ uint8_t pins;
+
+ uint8_t ctrl;
+ uint16_t io;
+ int cycle;
+};
+
+/* Register bitfields */
+enum md_opt {
+ OPT_MODE_MMAP = 0,
+ OPT_MODE_IOMAP16 = 1,
+ OPT_MODE_IOMAP1 = 2,
+ OPT_MODE_IOMAP2 = 3,
+ OPT_MODE = 0x3f,
+ OPT_LEVIREQ = 0x40,
+ OPT_SRESET = 0x80,
+};
+enum md_cstat {
+ STAT_INT = 0x02,
+ STAT_PWRDWN = 0x04,
+ STAT_XE = 0x10,
+ STAT_IOIS8 = 0x20,
+ STAT_SIGCHG = 0x40,
+ STAT_CHANGED = 0x80,
+};
+enum md_pins {
+ PINS_MRDY = 0x02,
+ PINS_CRDY = 0x20,
+};
+enum md_ctrl {
+ CTRL_IEN = 0x02,
+ CTRL_SRST = 0x04,
+};
+
+static inline void md_interrupt_update(struct md_s *s)
+{
+ if (!s->card.slot)
+ return;
+
+ qemu_set_irq(s->card.slot->irq,
+ !(s->stat & STAT_INT) && /* Inverted */
+ !(s->ctrl & (CTRL_IEN | CTRL_SRST)) &&
+ !(s->opt & OPT_SRESET));
+}
+
+static void md_set_irq(void *opaque, int irq, int level)
+{
+ struct md_s *s = (struct md_s *) opaque;
+ if (level)
+ s->stat |= STAT_INT;
+ else
+ s->stat &= ~STAT_INT;
+
+ md_interrupt_update(s);
+}
+
+static void md_reset(struct md_s *s)
+{
+ s->opt = OPT_MODE_MMAP;
+ s->stat = 0;
+ s->pins = 0;
+ s->cycle = 0;
+ s->ctrl = 0;
+ ide_reset(s->ide);
+}
+
+static uint8_t md_attr_read(void *opaque, uint32_t at)
+{
+ struct md_s *s = (struct md_s *) opaque;
+ if (at < s->attr_base) {
+ if (at < s->card.cis_len)
+ return s->card.cis[at];
+ else
+ return 0x00;
+ }
+
+ at -= s->attr_base;
+
+ switch (at) {
+ case 0x00: /* Configuration Option Register */
+ return s->opt;
+ case 0x02: /* Card Configuration Status Register */
+ if (s->ctrl & CTRL_IEN)
+ return s->stat & ~STAT_INT;
+ else
+ return s->stat;
+ case 0x04: /* Pin Replacement Register */
+ return (s->pins & PINS_CRDY) | 0x0c;
+ case 0x06: /* Socket and Copy Register */
+ return 0x00;
+#ifdef VERBOSE
+ default:
+ printf("%s: Bad attribute space register %02x\n", __FUNCTION__, at);
+#endif
+ }
+
+ return 0;
+}
+
+static void md_attr_write(void *opaque, uint32_t at, uint8_t value)
+{
+ struct md_s *s = (struct md_s *) opaque;
+ at -= s->attr_base;
+
+ switch (at) {
+ case 0x00: /* Configuration Option Register */
+ s->opt = value & 0xcf;
+ if (value & OPT_SRESET)
+ md_reset(s);
+ md_interrupt_update(s);
+ break;
+ case 0x02: /* Card Configuration Status Register */
+ if ((s->stat ^ value) & STAT_PWRDWN)
+ s->pins |= PINS_CRDY;
+ s->stat &= 0x82;
+ s->stat |= value & 0x74;
+ md_interrupt_update(s);
+ /* Word 170 in Identify Device must be equal to STAT_XE */
+ break;
+ case 0x04: /* Pin Replacement Register */
+ s->pins &= PINS_CRDY;
+ s->pins |= value & PINS_MRDY;
+ break;
+ case 0x06: /* Socket and Copy Register */
+ break;
+ default:
+ printf("%s: Bad attribute space register %02x\n", __FUNCTION__, at);
+ }
+}
+
+static uint16_t md_common_read(void *opaque, uint32_t at)
+{
+ struct md_s *s = (struct md_s *) opaque;
+ uint16_t ret;
+ at -= s->io_base;
+
+ switch (s->opt & OPT_MODE) {
+ case OPT_MODE_MMAP:
+ if ((at & ~0x3ff) == 0x400)
+ at = 0;
+ break;
+ case OPT_MODE_IOMAP16:
+ at &= 0xf;
+ break;
+ case OPT_MODE_IOMAP1:
+ if ((at & ~0xf) == 0x3f0)
+ at -= 0x3e8;
+ else if ((at & ~0xf) == 0x1f0)
+ at -= 0x1f0;
+ break;
+ case OPT_MODE_IOMAP2:
+ if ((at & ~0xf) == 0x370)
+ at -= 0x368;
+ else if ((at & ~0xf) == 0x170)
+ at -= 0x170;
+ }
+
+ switch (at) {
+ case 0x0: /* Even RD Data */
+ case 0x8:
+ return ide_data_readw(s->ide, 0);
+
+ /* TODO: 8-bit accesses */
+ if (s->cycle)
+ ret = s->io >> 8;
+ else {
+ s->io = ide_data_readw(s->ide, 0);
+ ret = s->io & 0xff;
+ }
+ s->cycle = !s->cycle;
+ return ret;
+ case 0x9: /* Odd RD Data */
+ return s->io >> 8;
+ case 0xd: /* Error */
+ return ide_ioport_read(s->ide, 0x1);
+ case 0xe: /* Alternate Status */
+ if (s->ide->cur_drive->bs)
+ return s->ide->cur_drive->status;
+ else
+ return 0;
+ case 0xf: /* Device Address */
+ return 0xc2 | ((~s->ide->select << 2) & 0x3c);
+ default:
+ return ide_ioport_read(s->ide, at);
+ }
+
+ return 0;
+}
+
+static void md_common_write(void *opaque, uint32_t at, uint16_t value)
+{
+ struct md_s *s = (struct md_s *) opaque;
+ at -= s->io_base;
+
+ switch (s->opt & OPT_MODE) {
+ case OPT_MODE_MMAP:
+ if ((at & ~0x3ff) == 0x400)
+ at = 0;
+ break;
+ case OPT_MODE_IOMAP16:
+ at &= 0xf;
+ break;
+ case OPT_MODE_IOMAP1:
+ if ((at & ~0xf) == 0x3f0)
+ at -= 0x3e8;
+ else if ((at & ~0xf) == 0x1f0)
+ at -= 0x1f0;
+ break;
+ case OPT_MODE_IOMAP2:
+ if ((at & ~0xf) == 0x370)
+ at -= 0x368;
+ else if ((at & ~0xf) == 0x170)
+ at -= 0x170;
+ }
+
+ switch (at) {
+ case 0x0: /* Even WR Data */
+ case 0x8:
+ ide_data_writew(s->ide, 0, value);
+ break;
+
+ /* TODO: 8-bit accesses */
+ if (s->cycle)
+ ide_data_writew(s->ide, 0, s->io | (value << 8));
+ else
+ s->io = value & 0xff;
+ s->cycle = !s->cycle;
+ break;
+ case 0x9:
+ s->io = value & 0xff;
+ s->cycle = !s->cycle;
+ break;
+ case 0xd: /* Features */
+ ide_ioport_write(s->ide, 0x1, value);
+ break;
+ case 0xe: /* Device Control */
+ s->ctrl = value;
+ if (value & CTRL_SRST)
+ md_reset(s);
+ md_interrupt_update(s);
+ break;
+ default:
+ if (s->stat & STAT_PWRDWN) {
+ s->pins |= PINS_CRDY;
+ s->stat &= ~STAT_PWRDWN;
+ }
+ ide_ioport_write(s->ide, at, value);
+ }
+}
+
+static const uint8_t dscm1xxxx_cis[0x14a] = {
+ [0x000] = CISTPL_DEVICE, /* 5V Device Information */
+ [0x002] = 0x03, /* Tuple length = 4 bytes */
+ [0x004] = 0xdb, /* ID: DTYPE_FUNCSPEC, non WP, DSPEED_150NS */
+ [0x006] = 0x01, /* Size = 2K bytes */
+ [0x008] = CISTPL_ENDMARK,
+
+ [0x00a] = CISTPL_DEVICE_OC, /* Additional Device Information */
+ [0x00c] = 0x04, /* Tuple length = 4 byest */
+ [0x00e] = 0x03, /* Conditions: Ext = 0, Vcc 3.3V, MWAIT = 1 */
+ [0x010] = 0xdb, /* ID: DTYPE_FUNCSPEC, non WP, DSPEED_150NS */
+ [0x012] = 0x01, /* Size = 2K bytes */
+ [0x014] = CISTPL_ENDMARK,
+
+ [0x016] = CISTPL_JEDEC_C, /* JEDEC ID */
+ [0x018] = 0x02, /* Tuple length = 2 bytes */
+ [0x01a] = 0xdf, /* PC Card ATA with no Vpp required */
+ [0x01c] = 0x01,
+
+ [0x01e] = CISTPL_MANFID, /* Manufacture ID */
+ [0x020] = 0x04, /* Tuple length = 4 bytes */
+ [0x022] = 0xa4, /* TPLMID_MANF = 00a4 (IBM) */
+ [0x024] = 0x00,
+ [0x026] = 0x00, /* PLMID_CARD = 0000 */
+ [0x028] = 0x00,
+
+ [0x02a] = CISTPL_VERS_1, /* Level 1 Version */
+ [0x02c] = 0x12, /* Tuple length = 23 bytes */
+ [0x02e] = 0x04, /* Major Version = JEIDA 4.2 / PCMCIA 2.1 */
+ [0x030] = 0x01, /* Minor Version = 1 */
+ [0x032] = 'I',
+ [0x034] = 'B',
+ [0x036] = 'M',
+ [0x038] = 0x00,
+ [0x03a] = 'm',
+ [0x03c] = 'i',
+ [0x03e] = 'c',
+ [0x040] = 'r',
+ [0x042] = 'o',
+ [0x044] = 'd',
+ [0x046] = 'r',
+ [0x048] = 'i',
+ [0x04a] = 'v',
+ [0x04c] = 'e',
+ [0x04e] = 0x00,
+ [0x050] = CISTPL_ENDMARK,
+
+ [0x052] = CISTPL_FUNCID, /* Function ID */
+ [0x054] = 0x02, /* Tuple length = 2 bytes */
+ [0x056] = 0x04, /* TPLFID_FUNCTION = Fixed Disk */
+ [0x058] = 0x01, /* TPLFID_SYSINIT: POST = 1, ROM = 0 */
+
+ [0x05a] = CISTPL_FUNCE, /* Function Extension */
+ [0x05c] = 0x02, /* Tuple length = 2 bytes */
+ [0x05e] = 0x01, /* TPLFE_TYPE = Disk Device Interface */
+ [0x060] = 0x01, /* TPLFE_DATA = PC Card ATA Interface */
+
+ [0x062] = CISTPL_FUNCE, /* Function Extension */
+ [0x064] = 0x03, /* Tuple length = 3 bytes */
+ [0x066] = 0x02, /* TPLFE_TYPE = Basic PC Card ATA Interface */
+ [0x068] = 0x08, /* TPLFE_DATA: Rotating, Unique, Single */
+ [0x06a] = 0x0f, /* TPLFE_DATA: Sleep, Standby, Idle, Auto */
+
+ [0x06c] = CISTPL_CONFIG, /* Configuration */
+ [0x06e] = 0x05, /* Tuple length = 5 bytes */
+ [0x070] = 0x01, /* TPCC_RASZ = 2 bytes, TPCC_RMSZ = 1 byte */
+ [0x072] = 0x07, /* TPCC_LAST = 7 */
+ [0x074] = 0x00, /* TPCC_RADR = 0200 */
+ [0x076] = 0x02,
+ [0x078] = 0x0f, /* TPCC_RMSK = 200, 202, 204, 206 */
+
+ [0x07a] = CISTPL_CFTABLE_ENTRY, /* 16-bit PC Card Configuration */
+ [0x07c] = 0x0b, /* Tuple length = 11 bytes */
+ [0x07e] = 0xc0, /* TPCE_INDX = Memory Mode, Default, Iface */
+ [0x080] = 0xc0, /* TPCE_IF = Memory, no BVDs, no WP, READY */
+ [0x082] = 0xa1, /* TPCE_FS = Vcc only, no I/O, Memory, Misc */
+ [0x084] = 0x27, /* NomV = 1, MinV = 1, MaxV = 1, Peakl = 1 */
+ [0x086] = 0x55, /* NomV: 5.0 V */
+ [0x088] = 0x4d, /* MinV: 4.5 V */
+ [0x08a] = 0x5d, /* MaxV: 5.5 V */
+ [0x08c] = 0x4e, /* Peakl: 450 mA */
+ [0x08e] = 0x08, /* TPCE_MS = 1 window, 1 byte, Host address */
+ [0x090] = 0x00, /* Window descriptor: Window length = 0 */
+ [0x092] = 0x20, /* TPCE_MI: support power down mode, RW */
+
+ [0x094] = CISTPL_CFTABLE_ENTRY, /* 16-bit PC Card Configuration */
+ [0x096] = 0x06, /* Tuple length = 6 bytes */
+ [0x098] = 0x00, /* TPCE_INDX = Memory Mode, no Default */
+ [0x09a] = 0x01, /* TPCE_FS = Vcc only, no I/O, no Memory */
+ [0x09c] = 0x21, /* NomV = 1, MinV = 0, MaxV = 0, Peakl = 1 */
+ [0x09e] = 0xb5, /* NomV: 3.3 V */
+ [0x0a0] = 0x1e,
+ [0x0a2] = 0x3e, /* Peakl: 350 mA */
+
+ [0x0a4] = CISTPL_CFTABLE_ENTRY, /* 16-bit PC Card Configuration */
+ [0x0a6] = 0x0d, /* Tuple length = 13 bytes */
+ [0x0a8] = 0xc1, /* TPCE_INDX = I/O and Memory Mode, Default */
+ [0x0aa] = 0x41, /* TPCE_IF = I/O and Memory, no BVD, no WP */
+ [0x0ac] = 0x99, /* TPCE_FS = Vcc only, I/O, Interrupt, Misc */
+ [0x0ae] = 0x27, /* NomV = 1, MinV = 1, MaxV = 1, Peakl = 1 */
+ [0x0b0] = 0x55, /* NomV: 5.0 V */
+ [0x0b2] = 0x4d, /* MinV: 4.5 V */
+ [0x0b4] = 0x5d, /* MaxV: 5.5 V */
+ [0x0b6] = 0x4e, /* Peakl: 450 mA */
+ [0x0b8] = 0x64, /* TPCE_IO = 16-byte boundary, 16/8 accesses */
+ [0x0ba] = 0xf0, /* TPCE_IR = MASK, Level, Pulse, Share */
+ [0x0bc] = 0xff, /* IRQ0..IRQ7 supported */
+ [0x0be] = 0xff, /* IRQ8..IRQ15 supported */
+ [0x0c0] = 0x20, /* TPCE_MI = support power down mode */
+
+ [0x0c2] = CISTPL_CFTABLE_ENTRY, /* 16-bit PC Card Configuration */
+ [0x0c4] = 0x06, /* Tuple length = 6 bytes */
+ [0x0c6] = 0x01, /* TPCE_INDX = I/O and Memory Mode */
+ [0x0c8] = 0x01, /* TPCE_FS = Vcc only, no I/O, no Memory */
+ [0x0ca] = 0x21, /* NomV = 1, MinV = 0, MaxV = 0, Peakl = 1 */
+ [0x0cc] = 0xb5, /* NomV: 3.3 V */
+ [0x0ce] = 0x1e,
+ [0x0d0] = 0x3e, /* Peakl: 350 mA */
+
+ [0x0d2] = CISTPL_CFTABLE_ENTRY, /* 16-bit PC Card Configuration */
+ [0x0d4] = 0x12, /* Tuple length = 18 bytes */
+ [0x0d6] = 0xc2, /* TPCE_INDX = I/O Primary Mode */
+ [0x0d8] = 0x41, /* TPCE_IF = I/O and Memory, no BVD, no WP */
+ [0x0da] = 0x99, /* TPCE_FS = Vcc only, I/O, Interrupt, Misc */
+ [0x0dc] = 0x27, /* NomV = 1, MinV = 1, MaxV = 1, Peakl = 1 */
+ [0x0de] = 0x55, /* NomV: 5.0 V */
+ [0x0e0] = 0x4d, /* MinV: 4.5 V */
+ [0x0e2] = 0x5d, /* MaxV: 5.5 V */
+ [0x0e4] = 0x4e, /* Peakl: 450 mA */
+ [0x0e6] = 0xea, /* TPCE_IO = 1K boundary, 16/8 access, Range */
+ [0x0e8] = 0x61, /* Range: 2 fields, 2 bytes addr, 1 byte len */
+ [0x0ea] = 0xf0, /* Field 1 address = 0x01f0 */
+ [0x0ec] = 0x01,
+ [0x0ee] = 0x07, /* Address block length = 8 */
+ [0x0f0] = 0xf6, /* Field 2 address = 0x03f6 */
+ [0x0f2] = 0x03,
+ [0x0f4] = 0x01, /* Address block length = 2 */
+ [0x0f6] = 0xee, /* TPCE_IR = IRQ E, Level, Pulse, Share */
+ [0x0f8] = 0x20, /* TPCE_MI = support power down mode */
+
+ [0x0fa] = CISTPL_CFTABLE_ENTRY, /* 16-bit PC Card Configuration */
+ [0x0fc] = 0x06, /* Tuple length = 6 bytes */
+ [0x0fe] = 0x02, /* TPCE_INDX = I/O Primary Mode, no Default */
+ [0x100] = 0x01, /* TPCE_FS = Vcc only, no I/O, no Memory */
+ [0x102] = 0x21, /* NomV = 1, MinV = 0, MaxV = 0, Peakl = 1 */
+ [0x104] = 0xb5, /* NomV: 3.3 V */
+ [0x106] = 0x1e,
+ [0x108] = 0x3e, /* Peakl: 350 mA */
+
+ [0x10a] = CISTPL_CFTABLE_ENTRY, /* 16-bit PC Card Configuration */
+ [0x10c] = 0x12, /* Tuple length = 18 bytes */
+ [0x10e] = 0xc3, /* TPCE_INDX = I/O Secondary Mode, Default */
+ [0x110] = 0x41, /* TPCE_IF = I/O and Memory, no BVD, no WP */
+ [0x112] = 0x99, /* TPCE_FS = Vcc only, I/O, Interrupt, Misc */
+ [0x114] = 0x27, /* NomV = 1, MinV = 1, MaxV = 1, Peakl = 1 */
+ [0x116] = 0x55, /* NomV: 5.0 V */
+ [0x118] = 0x4d, /* MinV: 4.5 V */
+ [0x11a] = 0x5d, /* MaxV: 5.5 V */
+ [0x11c] = 0x4e, /* Peakl: 450 mA */
+ [0x11e] = 0xea, /* TPCE_IO = 1K boundary, 16/8 access, Range */
+ [0x120] = 0x61, /* Range: 2 fields, 2 byte addr, 1 byte len */
+ [0x122] = 0x70, /* Field 1 address = 0x0170 */
+ [0x124] = 0x01,
+ [0x126] = 0x07, /* Address block length = 8 */
+ [0x128] = 0x76, /* Field 2 address = 0x0376 */
+ [0x12a] = 0x03,
+ [0x12c] = 0x01, /* Address block length = 2 */
+ [0x12e] = 0xee, /* TPCE_IR = IRQ E, Level, Pulse, Share */
+ [0x130] = 0x20, /* TPCE_MI = support power down mode */
+
+ [0x132] = CISTPL_CFTABLE_ENTRY, /* 16-bit PC Card Configuration */
+ [0x134] = 0x06, /* Tuple length = 6 bytes */
+ [0x136] = 0x03, /* TPCE_INDX = I/O Secondary Mode */
+ [0x138] = 0x01, /* TPCE_FS = Vcc only, no I/O, no Memory */
+ [0x13a] = 0x21, /* NomV = 1, MinV = 0, MaxV = 0, Peakl = 1 */
+ [0x13c] = 0xb5, /* NomV: 3.3 V */
+ [0x13e] = 0x1e,
+ [0x140] = 0x3e, /* Peakl: 350 mA */
+
+ [0x142] = CISTPL_NO_LINK, /* No Link */
+ [0x144] = 0x00, /* Tuple length = 0 bytes */
+
+ [0x146] = CISTPL_END, /* Tuple End */
+};
+
+static int dscm1xxxx_attach(void *opaque)
+{
+ struct md_s *md = (struct md_s *) opaque;
+ md->card.attr_read = md_attr_read;
+ md->card.attr_write = md_attr_write;
+ md->card.common_read = md_common_read;
+ md->card.common_write = md_common_write;
+ md->card.io_read = md_common_read;
+ md->card.io_write = md_common_write;
+
+ md->attr_base = md->card.cis[0x74] | (md->card.cis[0x76] << 8);
+ md->io_base = 0x0;
+
+ md_reset(md);
+ md_interrupt_update(md);
+
+ md->card.slot->card_string = "DSCM-1xxxx Hitachi Microdrive";
+ return 0;
+}
+
+static int dscm1xxxx_detach(void *opaque)
+{
+ struct md_s *md = (struct md_s *) opaque;
+ md_reset(md);
+ return 0;
+}
+
+struct pcmcia_card_s *dscm1xxxx_init(BlockDriverState *bdrv)
+{
+ struct md_s *md = (struct md_s *) qemu_mallocz(sizeof(struct md_s));
+ md->card.state = md;
+ md->card.attach = dscm1xxxx_attach;
+ md->card.detach = dscm1xxxx_detach;
+ md->card.cis = dscm1xxxx_cis;
+ md->card.cis_len = sizeof(dscm1xxxx_cis);
+
+ ide_init2(md->ide, bdrv, 0, qemu_allocate_irqs(md_set_irq, md, 1)[0]);
+ md->ide->is_cf = 1;
+ md->ide->mdata_size = METADATA_SIZE;
+ md->ide->mdata_storage = (uint8_t *) qemu_mallocz(METADATA_SIZE);
+ return &md->card;
+}
Modified: trunk/src/host/qemu-neo1973/hw/integratorcp.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/integratorcp.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/integratorcp.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -1,7 +1,7 @@
/*
* ARM Integrator CP System emulation.
*
- * Copyright (c) 2005-2006 CodeSourcery.
+ * Copyright (c) 2005-2007 CodeSourcery.
* Written by Paul Brook
*
* This code is licenced under the GPL
@@ -267,28 +267,22 @@
typedef struct icp_pic_state
{
- arm_pic_handler handler;
uint32_t base;
uint32_t level;
uint32_t irq_enabled;
uint32_t fiq_enabled;
- void *parent;
- int parent_irq;
- int parent_fiq;
+ qemu_irq parent_irq;
+ qemu_irq parent_fiq;
} icp_pic_state;
static void icp_pic_update(icp_pic_state *s)
{
uint32_t flags;
- if (s->parent_irq != -1) {
- flags = (s->level & s->irq_enabled);
- pic_set_irq_new(s->parent, s->parent_irq, flags != 0);
- }
- if (s->parent_fiq != -1) {
- flags = (s->level & s->fiq_enabled);
- pic_set_irq_new(s->parent, s->parent_fiq, flags != 0);
- }
+ flags = (s->level & s->irq_enabled);
+ qemu_set_irq(s->parent_irq, flags != 0);
+ flags = (s->level & s->fiq_enabled);
+ qemu_set_irq(s->parent_fiq, flags != 0);
}
static void icp_pic_set_irq(void *opaque, int irq, int level)
@@ -345,11 +339,11 @@
break;
case 4: /* INT_SOFTSET */
if (value & 1)
- pic_set_irq_new(s, 0, 1);
+ icp_pic_set_irq(s, 0, 1);
break;
case 5: /* INT_SOFTCLR */
if (value & 1)
- pic_set_irq_new(s, 0, 0);
+ icp_pic_set_irq(s, 0, 0);
break;
case 10: /* FRQ_ENABLESET */
s->fiq_enabled |= value;
@@ -380,25 +374,25 @@
icp_pic_write
};
-static icp_pic_state *icp_pic_init(uint32_t base, void *parent,
- int parent_irq, int parent_fiq)
+static qemu_irq *icp_pic_init(uint32_t base,
+ qemu_irq parent_irq, qemu_irq parent_fiq)
{
icp_pic_state *s;
int iomemtype;
+ qemu_irq *qi;
s = (icp_pic_state *)qemu_mallocz(sizeof(icp_pic_state));
if (!s)
return NULL;
- s->handler = icp_pic_set_irq;
+ qi = qemu_allocate_irqs(icp_pic_set_irq, s, 32);
s->base = base;
- s->parent = parent;
s->parent_irq = parent_irq;
s->parent_fiq = parent_fiq;
iomemtype = cpu_register_io_memory(0, icp_pic_readfn,
icp_pic_writefn, s);
cpu_register_physical_memory(base, 0x007fffff, iomemtype);
/* ??? Save/restore. */
- return s;
+ return qi;
}
/* CP control registers. */
@@ -471,15 +465,17 @@
static void integratorcp_init(int ram_size, int vga_ram_size, int boot_device,
DisplayState *ds, const char **fd_filename, int snapshot,
const char *kernel_filename, const char *kernel_cmdline,
- const char *initrd_filename, uint32_t cpuid)
+ const char *initrd_filename, const char *cpu_model)
{
CPUState *env;
uint32_t bios_offset;
- icp_pic_state *pic;
- void *cpu_pic;
+ qemu_irq *pic;
+ qemu_irq *cpu_pic;
env = cpu_init();
- cpu_arm_set_model(env, cpuid);
+ if (!cpu_model)
+ cpu_model = "arm926";
+ cpu_arm_set_model(env, cpu_model);
bios_offset = ram_size + vga_ram_size;
/* ??? On a real system the first 1Mb is mapped as SSRAM or boot flash. */
/* ??? RAM shoud repeat to fill physical memory space. */
@@ -490,57 +486,33 @@
integratorcm_init(ram_size >> 20, bios_offset);
cpu_pic = arm_pic_init_cpu(env);
- pic = icp_pic_init(0x14000000, cpu_pic, ARM_PIC_CPU_IRQ, ARM_PIC_CPU_FIQ);
- icp_pic_init(0xca000000, pic, 26, -1);
+ pic = icp_pic_init(0x14000000, cpu_pic[ARM_PIC_CPU_IRQ],
+ cpu_pic[ARM_PIC_CPU_FIQ]);
+ icp_pic_init(0xca000000, pic[26], NULL);
icp_pit_init(0x13000000, pic, 5);
- pl011_init(0x16000000, pic, 1, serial_hds[0]);
- pl011_init(0x17000000, pic, 2, serial_hds[1]);
+ pl011_init(0x16000000, pic[1], serial_hds[0]);
+ pl011_init(0x17000000, pic[2], serial_hds[1]);
icp_control_init(0xcb000000);
- pl050_init(0x18000000, pic, 3, 0);
- pl050_init(0x19000000, pic, 4, 1);
+ pl050_init(0x18000000, pic[3], 0);
+ pl050_init(0x19000000, pic[4], 1);
+ pl181_init(0x1c000000, sd_bdrv, pic[23], pic[24]);
if (nd_table[0].vlan) {
if (nd_table[0].model == NULL
|| strcmp(nd_table[0].model, "smc91c111") == 0) {
- smc91c111_init(&nd_table[0], 0xc8000000, pic, 27);
+ smc91c111_init(&nd_table[0], 0xc8000000, pic[27]);
} else {
fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model);
exit (1);
}
}
- pl110_init(ds, 0xc0000000, pic, 22, 0);
+ pl110_init(ds, 0xc0000000, pic[22], 0);
- arm_load_kernel(ram_size, kernel_filename, kernel_cmdline,
+ arm_load_kernel(env, ram_size, kernel_filename, kernel_cmdline,
initrd_filename, 0x113, 0x0);
}
-static void integratorcp926_init(int ram_size, int vga_ram_size,
- int boot_device, DisplayState *ds, const char **fd_filename, int snapshot,
- const char *kernel_filename, const char *kernel_cmdline,
- const char *initrd_filename)
-{
- integratorcp_init(ram_size, vga_ram_size, boot_device, ds, fd_filename,
- snapshot, kernel_filename, kernel_cmdline,
- initrd_filename, ARM_CPUID_ARM926);
-}
-
-static void integratorcp1026_init(int ram_size, int vga_ram_size,
- int boot_device, DisplayState *ds, const char **fd_filename, int snapshot,
- const char *kernel_filename, const char *kernel_cmdline,
- const char *initrd_filename)
-{
- integratorcp_init(ram_size, vga_ram_size, boot_device, ds, fd_filename,
- snapshot, kernel_filename, kernel_cmdline,
- initrd_filename, ARM_CPUID_ARM1026);
-}
-
-QEMUMachine integratorcp926_machine = {
- "integratorcp926",
+QEMUMachine integratorcp_machine = {
+ "integratorcp",
"ARM Integrator/CP (ARM926EJ-S)",
- integratorcp926_init,
+ integratorcp_init,
};
-
-QEMUMachine integratorcp1026_machine = {
- "integratorcp1026",
- "ARM Integrator/CP (ARM1026EJ-S)",
- integratorcp1026_init,
-};
Added: trunk/src/host/qemu-neo1973/hw/irq.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/irq.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/irq.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,57 @@
+/*
+ * QEMU IRQ/GPIO common code.
+ *
+ * Copyright (c) 2007 CodeSourcery.
+ *
+ * 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 "vl.h"
+
+struct IRQState {
+ qemu_irq_handler handler;
+ void *opaque;
+ int n;
+};
+
+void qemu_set_irq(qemu_irq irq, int level)
+{
+ if (!irq)
+ return;
+
+ irq->handler(irq->opaque, irq->n, level);
+}
+
+qemu_irq *qemu_allocate_irqs(qemu_irq_handler handler, void *opaque, int n)
+{
+ qemu_irq *s;
+ struct IRQState *p;
+ int i;
+
+ s = (qemu_irq *)qemu_mallocz(sizeof(qemu_irq) * n);
+ p = (struct IRQState *)qemu_mallocz(sizeof(struct IRQState) * n);
+ for (i = 0; i < n; i++) {
+ p->handler = handler;
+ p->opaque = opaque;
+ p->n = i;
+ s[i] = p;
+ p++;
+ }
+ return s;
+}
+
Added: trunk/src/host/qemu-neo1973/hw/irq.h
===================================================================
--- trunk/src/host/qemu-neo1973/hw/irq.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/irq.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,21 @@
+/* Generic IRQ/GPIO pin infrastructure. */
+
+typedef void (*qemu_irq_handler)(void *opaque, int n, int level);
+
+typedef struct IRQState *qemu_irq;
+
+void qemu_set_irq(qemu_irq irq, int level);
+
+static inline void qemu_irq_raise(qemu_irq irq)
+{
+ qemu_set_irq(irq, 1);
+}
+
+static inline void qemu_irq_lower(qemu_irq irq)
+{
+ qemu_set_irq(irq, 0);
+}
+
+/* Returns an array of N IRQs. */
+qemu_irq *qemu_allocate_irqs(qemu_irq_handler handler, void *opaque, int n);
+
Modified: trunk/src/host/qemu-neo1973/hw/lsi53c895a.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/lsi53c895a.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/lsi53c895a.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -251,7 +251,7 @@
uint32_t ia;
uint32_t sbc;
uint32_t csbc;
- uint32_t scratch[13]; /* SCRATCHA-SCRATCHR */
+ uint32_t scratch[18]; /* SCRATCHA-SCRATCHR */
/* Script ram is stored as 32-bit words in host byteorder. */
uint32_t script_ram[2048];
@@ -374,7 +374,7 @@
level, s->dstat, s->sist1, s->sist0);
last_level = level;
}
- pci_set_irq(&s->pci_dev, 0, level);
+ qemu_set_irq(s->pci_dev.irq[0], level);
}
/* Stop SCRIPTS execution and raise a SCSI interrupt. */
@@ -855,6 +855,7 @@
offset = sxt24(addr);
cpu_physical_memory_read(s->dsa + offset, (uint8_t *)buf, 8);
s->dbc = cpu_to_le32(buf[0]);
+ s->rbc = s->dbc;
addr = cpu_to_le32(buf[1]);
}
if ((s->sstat1 & PHASE_MASK) != ((insn >> 24) & 7)) {
@@ -864,6 +865,8 @@
break;
}
s->dnad = addr;
+ /* ??? Set ESA. */
+ s->ia = s->dsp - 8;
switch (s->sstat1 & 0x7) {
case PHASE_DO:
s->waiting = 2;
@@ -898,8 +901,6 @@
s->sbc = s->dbc;
s->rbc -= s->dbc;
s->ua = addr + s->dbc;
- /* ??? Set ESA. */
- s->ia = s->dsp - 8;
break;
case 1: /* IO or Read/Write instruction. */
@@ -1038,7 +1039,7 @@
op0 |= op1;
break;
case 3: /* XOR */
- op0 |= op1;
+ op0 ^= op1;
break;
case 4: /* AND */
op0 &= op1;
@@ -1046,6 +1047,7 @@
case 5: /* SHR */
op1 = op0 & 1;
op0 = (op0 >> 1) | (s->carry << 7);
+ s->carry = op1;
break;
case 6: /* ADD */
op0 += op1;
@@ -1388,7 +1390,7 @@
break;
case 0x02: /* SCNTL2 */
val &= ~(LSI_SCNTL2_WSR | LSI_SCNTL2_WSS);
- s->scntl3 = val;
+ s->scntl2 = val;
break;
case 0x03: /* SCNTL3 */
s->scntl3 = val;
@@ -1433,10 +1435,13 @@
if (val & LSI_ISTAT0_SRST) {
lsi_soft_reset(s);
}
+ break;
case 0x16: /* MBOX0 */
s->mbox0 = val;
+ break;
case 0x17: /* MBOX1 */
s->mbox1 = val;
+ break;
case 0x1b: /* CTEST3 */
s->ctest3 = val & 0x0f;
break;
@@ -1453,19 +1458,19 @@
}
s->ctest5 = val;
break;
- case 0x2c: /* DSPS[0:7] */
+ case 0x2c: /* DSP[0:7] */
s->dsp &= 0xffffff00;
s->dsp |= val;
break;
- case 0x2d: /* DSPS[8:15] */
+ case 0x2d: /* DSP[8:15] */
s->dsp &= 0xffff00ff;
s->dsp |= val << 8;
break;
- case 0x2e: /* DSPS[16:23] */
+ case 0x2e: /* DSP[16:23] */
s->dsp &= 0xff00ffff;
s->dsp |= val << 16;
break;
- case 0x2f: /* DSPS[14:31] */
+ case 0x2f: /* DSP[24:31] */
s->dsp &= 0x00ffffff;
s->dsp |= val << 24;
if ((s->dmode & LSI_DMODE_MAN) == 0
@@ -1765,7 +1770,7 @@
lsi_reg_writeb(s, addr, val & 0xff);
lsi_reg_writeb(s, addr + 1, (val >> 8) & 0xff);
lsi_reg_writeb(s, addr + 2, (val >> 16) & 0xff);
- lsi_reg_writeb(s, addr + 2, (val >> 24) & 0xff);
+ lsi_reg_writeb(s, addr + 3, (val >> 24) & 0xff);
}
static void lsi_io_mapfunc(PCIDevice *pci_dev, int region_num,
Modified: trunk/src/host/qemu-neo1973/hw/m48t59.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/m48t59.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/m48t59.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -1,7 +1,7 @@
/*
* QEMU M48T59 and M48T08 NVRAM emulation for PPC PREP and Sparc platforms
*
- * Copyright (c) 2003-2005 Jocelyn Mayer
+ * Copyright (c) 2003-2005, 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
@@ -41,7 +41,7 @@
/* Model parameters */
int type; // 8 = m48t08, 59 = m48t59
/* Hardware parameters */
- int IRQ;
+ qemu_irq IRQ;
int mem_index;
uint32_t mem_base;
uint32_t io_base;
@@ -100,7 +100,7 @@
uint64_t next_time;
m48t59_t *NVRAM = opaque;
- pic_set_irq(NVRAM->IRQ, 1);
+ qemu_set_irq(NVRAM->IRQ, 1);
if ((NVRAM->buffer[0x1FF5] & 0x80) == 0 &&
(NVRAM->buffer[0x1FF4] & 0x80) == 0 &&
(NVRAM->buffer[0x1FF3] & 0x80) == 0 &&
@@ -137,7 +137,7 @@
next_time = 1 + mktime(&tm_now);
}
qemu_mod_timer(NVRAM->alrm_timer, next_time * 1000);
- pic_set_irq(NVRAM->IRQ, 0);
+ qemu_set_irq(NVRAM->IRQ, 0);
}
@@ -173,8 +173,8 @@
/* May it be a hw CPU Reset instead ? */
qemu_system_reset_request();
} else {
- pic_set_irq(NVRAM->IRQ, 1);
- pic_set_irq(NVRAM->IRQ, 0);
+ qemu_set_irq(NVRAM->IRQ, 1);
+ qemu_set_irq(NVRAM->IRQ, 0);
}
}
@@ -575,12 +575,47 @@
&nvram_readl,
};
+static void m48t59_save(QEMUFile *f, void *opaque)
+{
+ m48t59_t *s = opaque;
+
+ qemu_put_8s(f, &s->lock);
+ qemu_put_be16s(f, &s->addr);
+ qemu_put_buffer(f, s->buffer, s->size);
+}
+
+static int m48t59_load(QEMUFile *f, void *opaque, int version_id)
+{
+ m48t59_t *s = opaque;
+
+ if (version_id != 1)
+ return -EINVAL;
+
+ qemu_get_8s(f, &s->lock);
+ qemu_get_be16s(f, &s->addr);
+ qemu_get_buffer(f, s->buffer, s->size);
+
+ return 0;
+}
+
+static void m48t59_reset(void *opaque)
+{
+ m48t59_t *NVRAM = opaque;
+
+ if (NVRAM->alrm_timer != NULL)
+ qemu_del_timer(NVRAM->alrm_timer);
+
+ if (NVRAM->wd_timer != NULL)
+ qemu_del_timer(NVRAM->wd_timer);
+}
+
/* Initialisation routine */
-m48t59_t *m48t59_init (int IRQ, target_ulong mem_base,
+m48t59_t *m48t59_init (qemu_irq IRQ, target_ulong mem_base,
uint32_t io_base, uint16_t size,
int type)
{
m48t59_t *s;
+ target_ulong save_base;
s = qemu_mallocz(sizeof(m48t59_t));
if (!s)
@@ -610,5 +645,9 @@
}
s->lock = 0;
+ qemu_register_reset(m48t59_reset, s);
+ save_base = mem_base ? mem_base : io_base;
+ register_savevm("m48t59", save_base, 1, m48t59_save, m48t59_load, s);
+
return s;
}
Modified: trunk/src/host/qemu-neo1973/hw/m48t59.h
===================================================================
--- trunk/src/host/qemu-neo1973/hw/m48t59.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/m48t59.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -6,7 +6,7 @@
void m48t59_write (m48t59_t *NVRAM, uint32_t addr, uint32_t val);
uint32_t m48t59_read (m48t59_t *NVRAM, uint32_t addr);
void m48t59_toggle_lock (m48t59_t *NVRAM, int lock);
-m48t59_t *m48t59_init (int IRQ, target_ulong mem_base,
+m48t59_t *m48t59_init (qemu_irq IRQ, target_ulong mem_base,
uint32_t io_base, uint16_t size,
int type);
Modified: trunk/src/host/qemu-neo1973/hw/max111x.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/max111x.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/max111x.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -1,17 +1,16 @@
/*
- * MAX1110/1111 ADC chip emulation.
+ * Maxim MAX1110/1111 ADC chip emulation.
*
* Copyright (c) 2006 Openedhand Ltd.
* Written by Andrzej Zaborowski <balrog at zabor.org>
*
- * This code is licensed under the GPLv2.
+ * This code is licensed under the GNU GPLv2.
*/
#include <vl.h>
struct max111x_s {
- void (*interrupt)(void *opaque);
- void *opaque;
+ qemu_irq interrupt;
uint8_t tb1, rb2, rb3;
int cycle;
@@ -87,10 +86,10 @@
s->rb3 = (measure << 6) & 0xc0;
if (s->interrupt)
- s->interrupt(s->opaque);
+ qemu_irq_raise(s->interrupt);
}
-struct max111x_s *max111x_init(void (*cb)(void *opaque), void *opaque)
+static struct max111x_s *max111x_init(qemu_irq cb)
{
struct max111x_s *s;
s = (struct max111x_s *)
@@ -98,7 +97,6 @@
memset(s, 0, sizeof(struct max111x_s));
s->interrupt = cb;
- s->opaque = opaque;
/* TODO: add a user interface for setting these */
s->input[0] = 0xf0;
@@ -113,16 +111,16 @@
return s;
}
-struct max111x_s *max1110_init(void (*cb)(void *opaque), void *opaque)
+struct max111x_s *max1110_init(qemu_irq cb)
{
- struct max111x_s *s = max111x_init(cb, opaque);
+ struct max111x_s *s = max111x_init(cb);
s->inputs = 8;
return s;
}
-struct max111x_s *max1111_init(void (*cb)(void *opaque), void *opaque)
+struct max111x_s *max1111_init(qemu_irq cb)
{
- struct max111x_s *s = max111x_init(cb, opaque);
+ struct max111x_s *s = max111x_init(cb);
s->inputs = 4;
return s;
}
Modified: trunk/src/host/qemu-neo1973/hw/max7310.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/max7310.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/max7310.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -10,22 +10,24 @@
#include "vl.h"
struct max7310_s {
+ i2c_slave i2c;
+ int i2c_command_byte;
+ int len;
+
uint8_t level;
uint8_t direction;
uint8_t polarity;
uint8_t status;
uint8_t command;
- int i2c_dir;
- struct i2c_slave_s i2c;
struct {
gpio_handler_t fn;
void *opaque;
} handler[8];
};
-void max7310_reset(struct i2c_slave_s *i2c)
+void max7310_reset(i2c_slave *i2c)
{
- struct max7310_s *s = (struct max7310_s *) i2c->opaque;
+ struct max7310_s *s = (struct max7310_s *) i2c;
s->level &= s->direction;
s->direction = 0xff;
s->polarity = 0xf0;
@@ -33,91 +35,87 @@
s->command = 0x00;
}
-static void max7310_start(void *opaque, int dir)
+static int max7310_rx(i2c_slave *i2c)
{
- struct max7310_s *s = (struct max7310_s *) opaque;
- s->i2c_dir = dir;
-}
+ struct max7310_s *s = (struct max7310_s *) i2c;
-static int max7310_read(void *opaque, uint8_t *data, int len)
-{
- struct max7310_s *s = (struct max7310_s *) opaque;
-
switch (s->command) {
case 0x00: /* Input port */
- memset(data, s->level ^ s->polarity, len);
+ return s->level ^ s->polarity;
break;
case 0x01: /* Output port */
- memset(data, s->level & ~s->direction, len);
+ return s->level & ~s->direction;
break;
case 0x02: /* Polarity inversion */
- memset(data, s->polarity, len);
- break;
+ return s->polarity;
case 0x03: /* Configuration */
- memset(data, s->direction, len);
- break;
+ return s->direction;
case 0x04: /* Timeout */
- memset(data, s->status, len);
+ return s->status;
break;
case 0xff: /* Reserved */
- memset(data, 0xff, len);
- break;
+ return 0xff;
default:
#ifdef VERBOSE
printf("%s: unknown register %02x\n", __FUNCTION__, s->command);
#endif
- return 1;
+ break;
}
- return 0;
+ return 0xff;
}
-static int max7310_write(void *opaque, uint8_t *data, int len)
+static int max7310_tx(i2c_slave *i2c, uint8_t data)
{
- struct max7310_s *s = (struct max7310_s *) opaque;
+ struct max7310_s *s = (struct max7310_s *) i2c;
uint8_t diff;
int line;
- if (len >= 1)
- s->command = data[0];
-
- if (len < 2) {
+ if (s->len ++ > 1) {
#ifdef VERBOSE
- printf("%s: message too short (%i bytes)\n", __FUNCTION__, len);
+ printf("%s: message too long (%i bytes)\n", __FUNCTION__, s->len);
#endif
+ return 1;
+ }
+
+ if (s->i2c_command_byte) {
+ s->command = data;
+ s->i2c_command_byte = 0;
return 0;
}
switch (s->command) {
case 0x01: /* Output port */
- for (diff = (data[1] ^ s->level) & ~s->direction; diff;
+ for (diff = (data ^ s->level) & ~s->direction; diff;
diff &= ~(1 << line)) {
line = ffs(diff) - 1;
if (s->handler[line].fn)
- s->handler[line].fn(line, (data[1] >> line) & 1,
+ s->handler[line].fn(line, (data >> line) & 1,
s->handler[line].opaque);
}
- s->level = (s->level & s->direction) | (data[1] & ~s->direction);
+ s->level = (s->level & s->direction) | (data & ~s->direction);
break;
case 0x02: /* Polarity inversion */
- s->polarity = data[1];
+ s->polarity = data;
break;
case 0x03: /* Configuration */
- s->level &= ~(s->direction ^ data[1]);
- s->direction = data[1];
+ s->level &= ~(s->direction ^ data);
+ s->direction = data;
break;
case 0x04: /* Timeout */
- s->status = data[1];
+ s->status = data;
break;
+ case 0x00: /* Input port - ignore writes */
+ break;
default:
#ifdef VERBOSE
printf("%s: unknown register %02x\n", __FUNCTION__, s->command);
@@ -128,33 +126,43 @@
return 0;
}
-static int max7310_tx(void *opaque, uint8_t *data, int len)
+static void max7310_event(i2c_slave *i2c, enum i2c_event event)
{
- struct max7310_s *s = (struct max7310_s *) opaque;
- if (len) {
- if (s->i2c_dir)
- return max7310_write(opaque, data, len);
- else
- return max7310_read(opaque, data, len);
+ struct max7310_s *s = (struct max7310_s *) i2c;
+ s->len = 0;
+
+ switch (event) {
+ case I2C_START_SEND:
+ s->i2c_command_byte = 1;
+ break;
+ case I2C_FINISH:
+ if (s->len == 1)
+#ifdef VERBOSE
+ printf("%s: message too short (%i bytes)\n", __FUNCTION__, s->len);
+#endif
+ break;
+ default:
+ break;
}
-
- return 0;
}
-struct i2c_slave_s *max7310_init(void)
+/* MAX7310 is SMBus-compatible (can be used with only SMBus protocols),
+ * but also accepts sequences that are not SMBus so return an I2C device. */
+struct i2c_slave *max7310_init(i2c_bus *bus)
{
- struct max7310_s *s = qemu_mallocz(sizeof(struct max7310_s));
- s->i2c.opaque = s;
- s->i2c.tx = max7310_tx;
- s->i2c.start = max7310_start;
+ struct max7310_s *s = (struct max7310_s *)
+ i2c_slave_init(bus, 0, sizeof(struct max7310_s));
+ s->i2c.event = max7310_event;
+ s->i2c.recv = max7310_rx;
+ s->i2c.send = max7310_tx;
max7310_reset(&s->i2c);
return &s->i2c;
}
-void max7310_gpio_set(struct i2c_slave_s *i2c, int line, int level)
+void max7310_gpio_set(i2c_slave *i2c, int line, int level)
{
- struct max7310_s *s = (struct max7310_s *) i2c->opaque;
+ struct max7310_s *s = (struct max7310_s *) i2c;
if (line >= sizeof(s->handler) / sizeof(*s->handler) || line < 0)
cpu_abort(cpu_single_env, "bad GPIO line");
@@ -164,10 +172,10 @@
s->level &= ~(s->direction & (1 << line));
}
-void max7310_gpio_handler_set(struct i2c_slave_s *i2c, int line,
+void max7310_gpio_handler_set(i2c_slave *i2c, int line,
gpio_handler_t handler, void *opaque)
{
- struct max7310_s *s = (struct max7310_s *) i2c->opaque;
+ struct max7310_s *s = (struct max7310_s *) i2c;
if (line >= sizeof(s->handler) / sizeof(*s->handler) || line < 0)
cpu_abort(cpu_single_env, "bad GPIO line");
Modified: trunk/src/host/qemu-neo1973/hw/mc146818rtc.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/mc146818rtc.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/mc146818rtc.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -54,7 +54,9 @@
uint8_t cmos_data[128];
uint8_t cmos_index;
struct tm current_tm;
- int irq;
+ qemu_irq irq;
+ target_phys_addr_t base;
+ int it_shift;
/* periodic timer */
QEMUTimer *periodic_timer;
int64_t next_periodic_time;
@@ -95,7 +97,7 @@
rtc_timer_update(s, s->next_periodic_time);
s->cmos_data[RTC_REG_C] |= 0xc0;
- pic_set_irq(s->irq, 1);
+ qemu_irq_raise(s->irq);
}
static void cmos_ioport_write(void *opaque, uint32_t addr, uint32_t data)
@@ -314,14 +316,14 @@
s->cmos_data[RTC_HOURS_ALARM] == s->current_tm.tm_hour)) {
s->cmos_data[RTC_REG_C] |= 0xa0;
- pic_set_irq(s->irq, 1);
+ qemu_irq_raise(s->irq);
}
}
/* update ended interrupt */
if (s->cmos_data[RTC_REG_B] & REG_B_UIE) {
s->cmos_data[RTC_REG_C] |= 0x90;
- pic_set_irq(s->irq, 1);
+ qemu_irq_raise(s->irq);
}
/* clear update in progress bit */
@@ -353,7 +355,7 @@
break;
case RTC_REG_C:
ret = s->cmos_data[s->cmos_index];
- pic_set_irq(s->irq, 0);
+ qemu_irq_lower(s->irq);
s->cmos_data[RTC_REG_C] = 0x00;
break;
default:
@@ -453,7 +455,7 @@
return 0;
}
-RTCState *rtc_init(int base, int irq)
+RTCState *rtc_init(int base, qemu_irq irq)
{
RTCState *s;
@@ -486,3 +488,109 @@
return s;
}
+/* Memory mapped interface */
+uint32_t cmos_mm_readb (void *opaque, target_phys_addr_t addr)
+{
+ RTCState *s = opaque;
+
+ return cmos_ioport_read(s, (addr - s->base) >> s->it_shift) & 0xFF;
+}
+
+void cmos_mm_writeb (void *opaque,
+ target_phys_addr_t addr, uint32_t value)
+{
+ RTCState *s = opaque;
+
+ cmos_ioport_write(s, (addr - s->base) >> s->it_shift, value & 0xFF);
+}
+
+uint32_t cmos_mm_readw (void *opaque, target_phys_addr_t addr)
+{
+ RTCState *s = opaque;
+ uint32_t val;
+
+ val = cmos_ioport_read(s, (addr - s->base) >> s->it_shift) & 0xFFFF;
+#ifdef TARGET_WORDS_BIGENDIAN
+ val = bswap16(val);
+#endif
+ return val;
+}
+
+void cmos_mm_writew (void *opaque,
+ target_phys_addr_t addr, uint32_t value)
+{
+ RTCState *s = opaque;
+#ifdef TARGET_WORDS_BIGENDIAN
+ value = bswap16(value);
+#endif
+ cmos_ioport_write(s, (addr - s->base) >> s->it_shift, value & 0xFFFF);
+}
+
+uint32_t cmos_mm_readl (void *opaque, target_phys_addr_t addr)
+{
+ RTCState *s = opaque;
+ uint32_t val;
+
+ val = cmos_ioport_read(s, (addr - s->base) >> s->it_shift);
+#ifdef TARGET_WORDS_BIGENDIAN
+ val = bswap32(val);
+#endif
+ return val;
+}
+
+void cmos_mm_writel (void *opaque,
+ target_phys_addr_t addr, uint32_t value)
+{
+ RTCState *s = opaque;
+#ifdef TARGET_WORDS_BIGENDIAN
+ value = bswap32(value);
+#endif
+ cmos_ioport_write(s, (addr - s->base) >> s->it_shift, value);
+}
+
+static CPUReadMemoryFunc *rtc_mm_read[] = {
+ &cmos_mm_readb,
+ &cmos_mm_readw,
+ &cmos_mm_readl,
+};
+
+static CPUWriteMemoryFunc *rtc_mm_write[] = {
+ &cmos_mm_writeb,
+ &cmos_mm_writew,
+ &cmos_mm_writel,
+};
+
+RTCState *rtc_mm_init(target_phys_addr_t base, int it_shift, qemu_irq irq)
+{
+ RTCState *s;
+ int io_memory;
+
+ s = qemu_mallocz(sizeof(RTCState));
+ if (!s)
+ return NULL;
+
+ s->irq = irq;
+ s->cmos_data[RTC_REG_A] = 0x26;
+ s->cmos_data[RTC_REG_B] = 0x02;
+ s->cmos_data[RTC_REG_C] = 0x00;
+ s->cmos_data[RTC_REG_D] = 0x80;
+ s->base = base;
+
+ rtc_set_date_from_host(s);
+
+ s->periodic_timer = qemu_new_timer(vm_clock,
+ rtc_periodic_timer, s);
+ s->second_timer = qemu_new_timer(vm_clock,
+ rtc_update_second, s);
+ s->second_timer2 = qemu_new_timer(vm_clock,
+ rtc_update_second2, s);
+
+ s->next_second_time = qemu_get_clock(vm_clock) + (ticks_per_sec * 99) / 100;
+ qemu_mod_timer(s->second_timer2, s->next_second_time);
+
+ io_memory = cpu_register_io_memory(0, rtc_mm_read, rtc_mm_write, s);
+ cpu_register_physical_memory(base, 2 << it_shift, io_memory);
+
+ register_savevm("mc146818rtc", base, 1, rtc_save, rtc_load, s);
+ return s;
+}
Deleted: trunk/src/host/qemu-neo1973/hw/md.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/md.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/md.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -1,499 +0,0 @@
-/*
- * DSCM-1XXXX Microdrive hard disk with CF+ II / PCMCIA interface.
- *
- * Copyright (c) 2006 Openedhand Ltd.
- * Written by Andrzej Zaborowski <balrog at zabor.org>
- *
- * This code is licensed under the GPLv2.
- */
-
-#include "vl.h"
-
-#define METADATA_SIZE 0x20
-
-struct md_s {
- IDEState ide[2];
- struct pcmcia_card_s card;
- uint32_t attr_base;
- uint32_t io_base;
-
- /* Card state */
- uint8_t opt;
- uint8_t stat;
- uint8_t pins;
-
- uint8_t ctrl;
- uint16_t io;
- int cycle;
-};
-
-/* Register bitfields */
-enum md_opt {
- OPT_MODE_MMAP = 0,
- OPT_MODE_IOMAP16 = 1,
- OPT_MODE_IOMAP1 = 2,
- OPT_MODE_IOMAP2 = 3,
- OPT_MODE = 0x3f,
- OPT_LEVIREQ = 0x40,
- OPT_SRESET = 0x80,
-};
-enum md_cstat {
- STAT_INT = 0x02,
- STAT_PWRDWN = 0x04,
- STAT_XE = 0x10,
- STAT_IOIS8 = 0x20,
- STAT_SIGCHG = 0x40,
- STAT_CHANGED = 0x80,
-};
-enum md_pins {
- PINS_MRDY = 0x02,
- PINS_CRDY = 0x20,
-};
-enum md_ctrl {
- CTRL_IEN = 0x02,
- CTRL_SRST = 0x04,
-};
-
-static inline void md_interrupt_update(struct md_s *s)
-{
- if (!s->card.slot)
- return;
-
- s->card.slot->set_irq(s->card.slot->opaque, 0,
- !(s->stat & STAT_INT) && /* Inverted */
- !(s->ctrl & (CTRL_IEN | CTRL_SRST)) &&
- !(s->opt & OPT_SRESET));
-}
-
-static void md_set_irq(void *opaque, int irq, int level)
-{
- struct md_s *s = (struct md_s *) opaque;
- if (level)
- s->stat |= STAT_INT;
- else
- s->stat &= ~STAT_INT;
-
- md_interrupt_update(s);
-}
-
-static void md_reset(struct md_s *s)
-{
- s->opt = OPT_MODE_MMAP;
- s->stat = 0;
- s->pins = 0;
- s->cycle = 0;
- s->ctrl = 0;
- ide_reset(s->ide);
-}
-
-static uint8_t md_attr_read(void *opaque, uint16_t at)
-{
- struct md_s *s = (struct md_s *) opaque;
- if (at < s->attr_base) {
- if (at < s->card.cis_len)
- return s->card.cis[at];
- else
- return 0x00;
- }
-
- at -= s->attr_base;
-
- switch (at) {
- case 0x00: /* Configuration Option Register */
- return s->opt;
- case 0x02: /* Card Configuration Status Register */
- if (s->ctrl & CTRL_IEN)
- return s->stat & ~STAT_INT;
- else
- return s->stat;
- case 0x04: /* Pin Replacement Register */
- return (s->pins & PINS_CRDY) | 0x0c;
- case 0x06: /* Socket and Copy Register */
- return 0x00;
-#ifdef VERBOSE
- default:
- printf("%s: Bad attribute space register %02x\n", __FUNCTION__, at);
-#endif
- }
-
- return 0;
-}
-
-static void md_attr_write(void *opaque, uint16_t at, uint8_t value)
-{
- struct md_s *s = (struct md_s *) opaque;
- at -= s->attr_base;
-
- switch (at) {
- case 0x00: /* Configuration Option Register */
- s->opt = value & 0xcf;
- if (value & OPT_SRESET)
- md_reset(s);
- md_interrupt_update(s);
- break;
- case 0x02: /* Card Configuration Status Register */
- if ((s->stat ^ value) & STAT_PWRDWN)
- s->pins |= PINS_CRDY;
- s->stat &= 0x82;
- s->stat |= value & 0x74;
- md_interrupt_update(s);
- /* Word 170 in Identify Device must be equal to STAT_XE */
- break;
- case 0x04: /* Pin Replacement Register */
- s->pins &= PINS_CRDY;
- s->pins |= value & PINS_MRDY;
- break;
- case 0x06: /* Socket and Copy Register */
- break;
- default:
- printf("%s: Bad attribute space register %02x\n", __FUNCTION__, at);
- }
-}
-
-static uint16_t md_common_read(void *opaque, uint16_t at)
-{
- struct md_s *s = (struct md_s *) opaque;
- uint16_t ret;
- at -= s->io_base;
-
- switch (s->opt & OPT_MODE) {
- case OPT_MODE_MMAP:
- if ((at & ~0x3ff) == 0x400)
- at = 0;
- break;
- case OPT_MODE_IOMAP16:
- at &= 0xf;
- break;
- case OPT_MODE_IOMAP1:
- if ((at & ~0xf) == 0x3f0)
- at -= 0x3e8;
- else if ((at & ~0xf) == 0x1f0)
- at -= 0x1f0;
- break;
- case OPT_MODE_IOMAP2:
- if ((at & ~0xf) == 0x370)
- at -= 0x368;
- else if ((at & ~0xf) == 0x170)
- at -= 0x170;
- }
-
- switch (at) {
- case 0x0: /* Even RD Data */
- case 0x8:
- return ide_data_readw(s->ide, 0);
-
- /* TODO: 8-bit accesses */
- if (s->cycle)
- ret = s->io >> 8;
- else {
- s->io = ide_data_readw(s->ide, 0);
- ret = s->io & 0xff;
- }
- s->cycle = !s->cycle;
- return ret;
- case 0x9: /* Odd RD Data */
- return s->io >> 8;
- case 0xd: /* Error */
- return ide_ioport_read(s->ide, 0x1);
- case 0xe: /* Alternate Status */
- if (s->ide->cur_drive->bs)
- return s->ide->cur_drive->status;
- else
- return 0;
- case 0xf: /* Device Address */
- return 0xc2 | ((~s->ide->select << 2) & 0x3c);
- default:
- return ide_ioport_read(s->ide, at);
- }
-
- return 0;
-}
-
-static void md_common_write(void *opaque, uint16_t at, uint16_t value)
-{
- struct md_s *s = (struct md_s *) opaque;
- at -= s->io_base;
-
- switch (s->opt & OPT_MODE) {
- case OPT_MODE_MMAP:
- if ((at & ~0x3ff) == 0x400)
- at = 0;
- break;
- case OPT_MODE_IOMAP16:
- at &= 0xf;
- break;
- case OPT_MODE_IOMAP1:
- if ((at & ~0xf) == 0x3f0)
- at -= 0x3e8;
- else if ((at & ~0xf) == 0x1f0)
- at -= 0x1f0;
- break;
- case OPT_MODE_IOMAP2:
- if ((at & ~0xf) == 0x370)
- at -= 0x368;
- else if ((at & ~0xf) == 0x170)
- at -= 0x170;
- }
-
- switch (at) {
- case 0x0: /* Even WR Data */
- case 0x8:
- ide_data_writew(s->ide, 0, value);
- break;
-
- /* TODO: 8-bit accesses */
- if (s->cycle)
- ide_data_writew(s->ide, 0, s->io | (value << 8));
- else
- s->io = value & 0xff;
- s->cycle = !s->cycle;
- break;
- case 0x9:
- s->io = value & 0xff;
- s->cycle = !s->cycle;
- break;
- case 0xd: /* Features */
- ide_ioport_write(s->ide, 0x1, value);
- break;
- case 0xe: /* Device Control */
- s->ctrl = value;
- if (value & CTRL_SRST)
- md_reset(s);
- md_interrupt_update(s);
- break;
- default:
- if (s->stat & STAT_PWRDWN) {
- s->pins |= PINS_CRDY;
- s->stat &= ~STAT_PWRDWN;
- }
- ide_ioport_write(s->ide, at, value);
- }
-}
-
-static const uint8_t dscm1xxxx_cis[0x14a] = {
- [0x000] = CISTPL_DEVICE, /* 5V Device Information */
- [0x002] = 0x03, /* Tuple length = 4 bytes */
- [0x004] = 0xdb, /* ID: DTYPE_FUNCSPEC, non WP, DSPEED_150NS */
- [0x006] = 0x01, /* Size = 2K bytes */
- [0x008] = CISTPL_ENDMARK,
-
- [0x00a] = CISTPL_DEVICE_OC, /* Additional Device Information */
- [0x00c] = 0x04, /* Tuple length = 4 byest */
- [0x00e] = 0x03, /* Conditions: Ext = 0, Vcc 3.3V, MWAIT = 1 */
- [0x010] = 0xdb, /* ID: DTYPE_FUNCSPEC, non WP, DSPEED_150NS */
- [0x012] = 0x01, /* Size = 2K bytes */
- [0x014] = CISTPL_ENDMARK,
-
- [0x016] = CISTPL_JEDEC_C, /* JEDEC ID */
- [0x018] = 0x02, /* Tuple length = 2 bytes */
- [0x01a] = 0xdf, /* PC Card ATA with no Vpp required */
- [0x01c] = 0x01,
-
- [0x01e] = CISTPL_MANFID, /* Manufacture ID */
- [0x020] = 0x04, /* Tuple length = 4 bytes */
- [0x022] = 0xa4, /* TPLMID_MANF = 00a4 (IBM) */
- [0x024] = 0x00,
- [0x026] = 0x00, /* PLMID_CARD = 0000 */
- [0x028] = 0x00,
-
- [0x02a] = CISTPL_VERS_1, /* Level 1 Version */
- [0x02c] = 0x12, /* Tuple length = 23 bytes */
- [0x02e] = 0x04, /* Major Version = JEIDA 4.2 / PCMCIA 2.1 */
- [0x030] = 0x01, /* Minor Version = 1 */
- [0x032] = 'I',
- [0x034] = 'B',
- [0x036] = 'M',
- [0x038] = 0x00,
- [0x03a] = 'm',
- [0x03c] = 'i',
- [0x03e] = 'c',
- [0x040] = 'r',
- [0x042] = 'o',
- [0x044] = 'd',
- [0x046] = 'r',
- [0x048] = 'i',
- [0x04a] = 'v',
- [0x04c] = 'e',
- [0x04e] = 0x00,
- [0x050] = CISTPL_ENDMARK,
-
- [0x052] = CISTPL_FUNCID, /* Function ID */
- [0x054] = 0x02, /* Tuple length = 2 bytes */
- [0x056] = 0x04, /* TPLFID_FUNCTION = Fixed Disk */
- [0x058] = 0x01, /* TPLFID_SYSINIT: POST = 1, ROM = 0 */
-
- [0x05a] = CISTPL_FUNCE, /* Function Extension */
- [0x05c] = 0x02, /* Tuple length = 2 bytes */
- [0x05e] = 0x01, /* TPLFE_TYPE = Disk Device Interface */
- [0x060] = 0x01, /* TPLFE_DATA = PC Card ATA Interface */
-
- [0x062] = CISTPL_FUNCE, /* Function Extension */
- [0x064] = 0x03, /* Tuple length = 3 bytes */
- [0x066] = 0x02, /* TPLFE_TYPE = Basic PC Card ATA Interface */
- [0x068] = 0x08, /* TPLFE_DATA: Rotating, Unique, Single */
- [0x06a] = 0x0f, /* TPLFE_DATA: Sleep, Standby, Idle, Auto */
-
- [0x06c] = CISTPL_CONFIG, /* Configuration */
- [0x06e] = 0x05, /* Tuple length = 5 bytes */
- [0x070] = 0x01, /* TPCC_RASZ = 2 bytes, TPCC_RMSZ = 1 byte */
- [0x072] = 0x07, /* TPCC_LAST = 7 */
- [0x074] = 0x00, /* TPCC_RADR = 0200 */
- [0x076] = 0x02,
- [0x078] = 0x0f, /* TPCC_RMSK = 200, 202, 204, 206 */
-
- [0x07a] = CISTPL_CFTABLE_ENTRY, /* 16-bit PC Card Configuration */
- [0x07c] = 0x0b, /* Tuple length = 11 bytes */
- [0x07e] = 0xc0, /* TPCE_INDX = Memory Mode, Default, Iface */
- [0x080] = 0xc0, /* TPCE_IF = Memory, no BVDs, no WP, READY */
- [0x082] = 0xa1, /* TPCE_FS = Vcc only, no I/O, Memory, Misc */
- [0x084] = 0x27, /* NomV = 1, MinV = 1, MaxV = 1, Peakl = 1 */
- [0x086] = 0x55, /* NomV: 5.0 V */
- [0x088] = 0x4d, /* MinV: 4.5 V */
- [0x08a] = 0x5d, /* MaxV: 5.5 V */
- [0x08c] = 0x4e, /* Peakl: 450 mA */
- [0x08e] = 0x08, /* TPCE_MS = 1 window, 1 byte, Host address */
- [0x090] = 0x00, /* Window descriptor: Window length = 0 */
- [0x092] = 0x20, /* TPCE_MI: support power down mode, RW */
-
- [0x094] = CISTPL_CFTABLE_ENTRY, /* 16-bit PC Card Configuration */
- [0x096] = 0x06, /* Tuple length = 6 bytes */
- [0x098] = 0x00, /* TPCE_INDX = Memory Mode, no Default */
- [0x09a] = 0x01, /* TPCE_FS = Vcc only, no I/O, no Memory */
- [0x09c] = 0x21, /* NomV = 1, MinV = 0, MaxV = 0, Peakl = 1 */
- [0x09e] = 0xb5, /* NomV: 3.3 V */
- [0x0a0] = 0x1e,
- [0x0a2] = 0x3e, /* Peakl: 350 mA */
-
- [0x0a4] = CISTPL_CFTABLE_ENTRY, /* 16-bit PC Card Configuration */
- [0x0a6] = 0x0d, /* Tuple length = 13 bytes */
- [0x0a8] = 0xc1, /* TPCE_INDX = I/O and Memory Mode, Default */
- [0x0aa] = 0x41, /* TPCE_IF = I/O and Memory, no BVD, no WP */
- [0x0ac] = 0x99, /* TPCE_FS = Vcc only, I/O, Interrupt, Misc */
- [0x0ae] = 0x27, /* NomV = 1, MinV = 1, MaxV = 1, Peakl = 1 */
- [0x0b0] = 0x55, /* NomV: 5.0 V */
- [0x0b2] = 0x4d, /* MinV: 4.5 V */
- [0x0b4] = 0x5d, /* MaxV: 5.5 V */
- [0x0b6] = 0x4e, /* Peakl: 450 mA */
- [0x0b8] = 0x64, /* TPCE_IO = 16-byte boundary, 16/8 accesses */
- [0x0ba] = 0xf0, /* TPCE_IR = MASK, Level, Pulse, Share */
- [0x0bc] = 0xff, /* IRQ0..IRQ7 supported */
- [0x0be] = 0xff, /* IRQ8..IRQ15 supported */
- [0x0c0] = 0x20, /* TPCE_MI = support power down mode */
-
- [0x0c2] = CISTPL_CFTABLE_ENTRY, /* 16-bit PC Card Configuration */
- [0x0c4] = 0x06, /* Tuple length = 6 bytes */
- [0x0c6] = 0x01, /* TPCE_INDX = I/O and Memory Mode */
- [0x0c8] = 0x01, /* TPCE_FS = Vcc only, no I/O, no Memory */
- [0x0ca] = 0x21, /* NomV = 1, MinV = 0, MaxV = 0, Peakl = 1 */
- [0x0cc] = 0xb5, /* NomV: 3.3 V */
- [0x0ce] = 0x1e,
- [0x0d0] = 0x3e, /* Peakl: 350 mA */
-
- [0x0d2] = CISTPL_CFTABLE_ENTRY, /* 16-bit PC Card Configuration */
- [0x0d4] = 0x12, /* Tuple length = 18 bytes */
- [0x0d6] = 0xc2, /* TPCE_INDX = I/O Primary Mode */
- [0x0d8] = 0x41, /* TPCE_IF = I/O and Memory, no BVD, no WP */
- [0x0da] = 0x99, /* TPCE_FS = Vcc only, I/O, Interrupt, Misc */
- [0x0dc] = 0x27, /* NomV = 1, MinV = 1, MaxV = 1, Peakl = 1 */
- [0x0de] = 0x55, /* NomV: 5.0 V */
- [0x0e0] = 0x4d, /* MinV: 4.5 V */
- [0x0e2] = 0x5d, /* MaxV: 5.5 V */
- [0x0e4] = 0x4e, /* Peakl: 450 mA */
- [0x0e6] = 0xea, /* TPCE_IO = 1K boundary, 16/8 access, Range */
- [0x0e8] = 0x61, /* Range: 2 fields, 2 bytes addr, 1 byte len */
- [0x0ea] = 0xf0, /* Field 1 address = 0x01f0 */
- [0x0ec] = 0x01,
- [0x0ee] = 0x07, /* Address block length = 8 */
- [0x0f0] = 0xf6, /* Field 2 address = 0x03f6 */
- [0x0f2] = 0x03,
- [0x0f4] = 0x01, /* Address block length = 2 */
- [0x0f6] = 0xee, /* TPCE_IR = IRQ E, Level, Pulse, Share */
- [0x0f8] = 0x20, /* TPCE_MI = support power down mode */
-
- [0x0fa] = CISTPL_CFTABLE_ENTRY, /* 16-bit PC Card Configuration */
- [0x0fc] = 0x06, /* Tuple length = 6 bytes */
- [0x0fe] = 0x02, /* TPCE_INDX = I/O Primary Mode, no Default */
- [0x100] = 0x01, /* TPCE_FS = Vcc only, no I/O, no Memory */
- [0x102] = 0x21, /* NomV = 1, MinV = 0, MaxV = 0, Peakl = 1 */
- [0x104] = 0xb5, /* NomV: 3.3 V */
- [0x106] = 0x1e,
- [0x108] = 0x3e, /* Peakl: 350 mA */
-
- [0x10a] = CISTPL_CFTABLE_ENTRY, /* 16-bit PC Card Configuration */
- [0x10c] = 0x12, /* Tuple length = 18 bytes */
- [0x10e] = 0xc3, /* TPCE_INDX = I/O Secondary Mode, Default */
- [0x110] = 0x41, /* TPCE_IF = I/O and Memory, no BVD, no WP */
- [0x112] = 0x99, /* TPCE_FS = Vcc only, I/O, Interrupt, Misc */
- [0x114] = 0x27, /* NomV = 1, MinV = 1, MaxV = 1, Peakl = 1 */
- [0x116] = 0x55, /* NomV: 5.0 V */
- [0x118] = 0x4d, /* MinV: 4.5 V */
- [0x11a] = 0x5d, /* MaxV: 5.5 V */
- [0x11c] = 0x4e, /* Peakl: 450 mA */
- [0x11e] = 0xea, /* TPCE_IO = 1K boundary, 16/8 access, Range */
- [0x120] = 0x61, /* Range: 2 fields, 2 byte addr, 1 byte len */
- [0x122] = 0x70, /* Field 1 address = 0x0170 */
- [0x124] = 0x01,
- [0x126] = 0x07, /* Address block length = 8 */
- [0x128] = 0x76, /* Field 2 address = 0x0376 */
- [0x12a] = 0x03,
- [0x12c] = 0x01, /* Address block length = 2 */
- [0x12e] = 0xee, /* TPCE_IR = IRQ E, Level, Pulse, Share */
- [0x130] = 0x20, /* TPCE_MI = support power down mode */
-
- [0x132] = CISTPL_CFTABLE_ENTRY, /* 16-bit PC Card Configuration */
- [0x134] = 0x06, /* Tuple length = 6 bytes */
- [0x136] = 0x03, /* TPCE_INDX = I/O Secondary Mode */
- [0x138] = 0x01, /* TPCE_FS = Vcc only, no I/O, no Memory */
- [0x13a] = 0x21, /* NomV = 1, MinV = 0, MaxV = 0, Peakl = 1 */
- [0x13c] = 0xb5, /* NomV: 3.3 V */
- [0x13e] = 0x1e,
- [0x140] = 0x3e, /* Peakl: 350 mA */
-
- [0x142] = CISTPL_NO_LINK, /* No Link */
- [0x144] = 0x00, /* Tuple length = 0 bytes */
-
- [0x146] = CISTPL_END, /* Tuple End */
-};
-
-static int dscm1xxxx_attach(void *opaque)
-{
- struct md_s *md = (struct md_s *) opaque;
- md->card.attr_read = md_attr_read;
- md->card.attr_write = md_attr_write;
- md->card.common_read = md_common_read;
- md->card.common_write = md_common_write;
- md->card.io_read = md_common_read;
- md->card.io_write = md_common_write;
-
- md->attr_base = md->card.cis[0x74] | (md->card.cis[0x76] << 8);
- md->io_base = 0x0;
-
- md_reset(md);
- md_interrupt_update(md);
-
- md->card.slot->card_string = "DSCM-1xxxx Hitachi Microdrive";
- return 0;
-}
-
-static int dscm1xxxx_detach(void *opaque)
-{
- struct md_s *md = (struct md_s *) opaque;
- md_reset(md);
- return 0;
-}
-
-struct pcmcia_card_s *dscm1xxxx_init(BlockDriverState *bdrv)
-{
- struct md_s *md = (struct md_s *) qemu_mallocz(sizeof(struct md_s));
- md->card.state = md;
- md->card.attach = dscm1xxxx_attach;
- md->card.detach = dscm1xxxx_detach;
- md->card.cis = dscm1xxxx_cis;
- md->card.cis_len = sizeof(dscm1xxxx_cis);
-
- ide_init2(md->ide, bdrv, 0, md_set_irq, md, 0);
- md->ide->is_cf = 1;
- md->ide->mdata_size = METADATA_SIZE;
- md->ide->mdata_storage = (uint8_t *) qemu_mallocz(METADATA_SIZE);
- return &md->card;
-}
Added: trunk/src/host/qemu-neo1973/hw/mips_int.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/mips_int.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/mips_int.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,44 @@
+#include "vl.h"
+#include "cpu.h"
+
+/* Raise IRQ to CPU if necessary. It must be called every time the active
+ IRQ may change */
+void cpu_mips_update_irq(CPUState *env)
+{
+ if ((env->CP0_Status & (1 << CP0St_IE)) &&
+ !(env->CP0_Status & (1 << CP0St_EXL)) &&
+ !(env->CP0_Status & (1 << CP0St_ERL)) &&
+ !(env->hflags & MIPS_HFLAG_DM)) {
+ if ((env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask) &&
+ !(env->interrupt_request & CPU_INTERRUPT_HARD)) {
+ cpu_interrupt(env, CPU_INTERRUPT_HARD);
+ }
+ } else
+ cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+}
+
+static void cpu_mips_irq_request(void *opaque, int irq, int level)
+{
+ CPUState *env = (CPUState *)opaque;
+
+ if (irq < 0 || irq > 7)
+ return;
+
+ if (level) {
+ env->CP0_Cause |= 1 << (irq + CP0Ca_IP);
+ } else {
+ env->CP0_Cause &= ~(1 << (irq + CP0Ca_IP));
+ }
+ cpu_mips_update_irq(env);
+}
+
+void cpu_mips_irq_init_cpu(CPUState *env)
+{
+ qemu_irq *qi;
+ int i;
+
+ qi = qemu_allocate_irqs(cpu_mips_irq_request, env, 8);
+ for (i = 0; i < 8; i++) {
+ env->irq[i] = qi[i];
+ }
+}
Added: trunk/src/host/qemu-neo1973/hw/mips_malta.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/mips_malta.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/mips_malta.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,883 @@
+/*
+ * QEMU Malta board support
+ *
+ * Copyright (c) 2006 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 "vl.h"
+
+#ifdef TARGET_WORDS_BIGENDIAN
+#define BIOS_FILENAME "mips_bios.bin"
+#else
+#define BIOS_FILENAME "mipsel_bios.bin"
+#endif
+
+#ifdef TARGET_MIPS64
+#define PHYS_TO_VIRT(x) ((x) | ~0x7fffffffULL)
+#else
+#define PHYS_TO_VIRT(x) ((x) | ~0x7fffffffU)
+#endif
+
+#define ENVP_ADDR (int32_t)0x80002000
+#define VIRT_TO_PHYS_ADDEND (-((int64_t)(int32_t)0x80000000))
+
+#define ENVP_NB_ENTRIES 16
+#define ENVP_ENTRY_SIZE 256
+
+
+extern FILE *logfile;
+
+typedef struct {
+ uint32_t leds;
+ uint32_t brk;
+ uint32_t gpout;
+ uint32_t i2cin;
+ uint32_t i2coe;
+ uint32_t i2cout;
+ uint32_t i2csel;
+ CharDriverState *display;
+ char display_text[9];
+ SerialState *uart;
+} MaltaFPGAState;
+
+static PITState *pit;
+
+/* Malta FPGA */
+static void malta_fpga_update_display(void *opaque)
+{
+ char leds_text[9];
+ int i;
+ MaltaFPGAState *s = opaque;
+
+ for (i = 7 ; i >= 0 ; i--) {
+ if (s->leds & (1 << i))
+ leds_text[i] = '#';
+ else
+ leds_text[i] = ' ';
+ }
+ leds_text[8] = '\0';
+
+ qemu_chr_printf(s->display, "\e[H\n\n|\e[32m%-8.8s\e[00m|\r\n", leds_text);
+ qemu_chr_printf(s->display, "\n\n\n\n|\e[31m%-8.8s\e[00m|", s->display_text);
+}
+
+/*
+ * EEPROM 24C01 / 24C02 emulation.
+ *
+ * Emulation for serial EEPROMs:
+ * 24C01 - 1024 bit (128 x 8)
+ * 24C02 - 2048 bit (256 x 8)
+ *
+ * Typical device names include Microchip 24C02SC or SGS Thomson ST24C02.
+ */
+
+//~ #define DEBUG
+
+#if defined(DEBUG)
+# define logout(fmt, args...) fprintf(stderr, "MALTA\t%-24s" fmt, __func__, ##args)
+#else
+# define logout(fmt, args...) ((void)0)
+#endif
+
+struct _eeprom24c0x_t {
+ uint8_t tick;
+ uint8_t address;
+ uint8_t command;
+ uint8_t ack;
+ uint8_t scl;
+ uint8_t sda;
+ uint8_t data;
+ //~ uint16_t size;
+ uint8_t contents[256];
+};
+
+typedef struct _eeprom24c0x_t eeprom24c0x_t;
+
+static eeprom24c0x_t eeprom = {
+ contents: {
+ /* 00000000: */ 0x80,0x08,0x04,0x0D,0x0A,0x01,0x40,0x00,
+ /* 00000008: */ 0x01,0x75,0x54,0x00,0x82,0x08,0x00,0x01,
+ /* 00000010: */ 0x8F,0x04,0x02,0x01,0x01,0x00,0x0E,0x00,
+ /* 00000018: */ 0x00,0x00,0x00,0x14,0x0F,0x14,0x2D,0x40,
+ /* 00000020: */ 0x15,0x08,0x15,0x08,0x00,0x00,0x00,0x00,
+ /* 00000028: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ /* 00000030: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ /* 00000038: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x12,0xD0,
+ /* 00000040: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ /* 00000048: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ /* 00000050: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ /* 00000058: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ /* 00000060: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ /* 00000068: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ /* 00000070: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
+ /* 00000078: */ 0x00,0x00,0x00,0x00,0x00,0x00,0x64,0xF4,
+ },
+};
+
+static uint8_t eeprom24c0x_read()
+{
+ logout("%u: scl = %u, sda = %u, data = 0x%02x\n",
+ eeprom.tick, eeprom.scl, eeprom.sda, eeprom.data);
+ return eeprom.sda;
+}
+
+static void eeprom24c0x_write(int scl, int sda)
+{
+ if (eeprom.scl && scl && (eeprom.sda != sda)) {
+ logout("%u: scl = %u->%u, sda = %u->%u i2c %s\n",
+ eeprom.tick, eeprom.scl, scl, eeprom.sda, sda, sda ? "stop" : "start");
+ if (!sda) {
+ eeprom.tick = 1;
+ eeprom.command = 0;
+ }
+ } else if (eeprom.tick == 0 && !eeprom.ack) {
+ /* Waiting for start. */
+ logout("%u: scl = %u->%u, sda = %u->%u wait for i2c start\n",
+ eeprom.tick, eeprom.scl, scl, eeprom.sda, sda);
+ } else if (!eeprom.scl && scl) {
+ logout("%u: scl = %u->%u, sda = %u->%u trigger bit\n",
+ eeprom.tick, eeprom.scl, scl, eeprom.sda, sda);
+ if (eeprom.ack) {
+ logout("\ti2c ack bit = 0\n");
+ sda = 0;
+ eeprom.ack = 0;
+ } else if (eeprom.sda == sda) {
+ uint8_t bit = (sda != 0);
+ logout("\ti2c bit = %d\n", bit);
+ if (eeprom.tick < 9) {
+ eeprom.command <<= 1;
+ eeprom.command += bit;
+ eeprom.tick++;
+ if (eeprom.tick == 9) {
+ logout("\tcommand 0x%04x, %s\n", eeprom.command, bit ? "read" : "write");
+ eeprom.ack = 1;
+ }
+ } else if (eeprom.tick < 17) {
+ if (eeprom.command & 1) {
+ sda = ((eeprom.data & 0x80) != 0);
+ }
+ eeprom.address <<= 1;
+ eeprom.address += bit;
+ eeprom.tick++;
+ eeprom.data <<= 1;
+ if (eeprom.tick == 17) {
+ eeprom.data = eeprom.contents[eeprom.address];
+ logout("\taddress 0x%04x, data 0x%02x\n", eeprom.address, eeprom.data);
+ eeprom.ack = 1;
+ eeprom.tick = 0;
+ }
+ } else if (eeprom.tick >= 17) {
+ sda = 0;
+ }
+ } else {
+ logout("\tsda changed with raising scl\n");
+ }
+ } else {
+ logout("%u: scl = %u->%u, sda = %u->%u\n", eeprom.tick, eeprom.scl, scl, eeprom.sda, sda);
+ }
+ eeprom.scl = scl;
+ eeprom.sda = sda;
+}
+
+static uint32_t malta_fpga_readl(void *opaque, target_phys_addr_t addr)
+{
+ MaltaFPGAState *s = opaque;
+ uint32_t val = 0;
+ uint32_t saddr;
+
+ saddr = (addr & 0xfffff);
+
+ switch (saddr) {
+
+ /* SWITCH Register */
+ case 0x00200:
+ val = 0x00000000; /* All switches closed */
+ break;
+
+ /* STATUS Register */
+ case 0x00208:
+#ifdef TARGET_WORDS_BIGENDIAN
+ val = 0x00000012;
+#else
+ val = 0x00000010;
+#endif
+ break;
+
+ /* JMPRS Register */
+ case 0x00210:
+ val = 0x00;
+ break;
+
+ /* LEDBAR Register */
+ case 0x00408:
+ val = s->leds;
+ break;
+
+ /* BRKRES Register */
+ case 0x00508:
+ val = s->brk;
+ break;
+
+ /* UART Registers */
+ case 0x00900:
+ case 0x00908:
+ case 0x00910:
+ case 0x00918:
+ case 0x00920:
+ case 0x00928:
+ case 0x00930:
+ case 0x00938:
+ val = serial_mm_readb(s->uart, addr);
+ break;
+
+ /* GPOUT Register */
+ case 0x00a00:
+ val = s->gpout;
+ break;
+
+ /* XXX: implement a real I2C controller */
+
+ /* GPINP Register */
+ case 0x00a08:
+ /* IN = OUT until a real I2C control is implemented */
+ if (s->i2csel)
+ val = s->i2cout;
+ else
+ val = 0x00;
+ break;
+
+ /* I2CINP Register */
+ case 0x00b00:
+ val = ((s->i2cin & ~1) | eeprom24c0x_read());
+ break;
+
+ /* I2COE Register */
+ case 0x00b08:
+ val = s->i2coe;
+ break;
+
+ /* I2COUT Register */
+ case 0x00b10:
+ val = s->i2cout;
+ break;
+
+ /* I2CSEL Register */
+ case 0x00b18:
+ val = s->i2csel;
+ break;
+
+ default:
+#if 0
+ printf ("malta_fpga_read: Bad register offset 0x" TARGET_FMT_lx "\n",
+ addr);
+#endif
+ break;
+ }
+ return val;
+}
+
+static void malta_fpga_writel(void *opaque, target_phys_addr_t addr,
+ uint32_t val)
+{
+ MaltaFPGAState *s = opaque;
+ uint32_t saddr;
+
+ saddr = (addr & 0xfffff);
+
+ switch (saddr) {
+
+ /* SWITCH Register */
+ case 0x00200:
+ break;
+
+ /* JMPRS Register */
+ case 0x00210:
+ break;
+
+ /* LEDBAR Register */
+ /* XXX: implement a 8-LED array */
+ case 0x00408:
+ s->leds = val & 0xff;
+ break;
+
+ /* ASCIIWORD Register */
+ case 0x00410:
+ snprintf(s->display_text, 9, "%08X", val);
+ malta_fpga_update_display(s);
+ break;
+
+ /* ASCIIPOS0 to ASCIIPOS7 Registers */
+ case 0x00418:
+ case 0x00420:
+ case 0x00428:
+ case 0x00430:
+ case 0x00438:
+ case 0x00440:
+ case 0x00448:
+ case 0x00450:
+ s->display_text[(saddr - 0x00418) >> 3] = (char) val;
+ malta_fpga_update_display(s);
+ break;
+
+ /* SOFTRES Register */
+ case 0x00500:
+ if (val == 0x42)
+ qemu_system_reset_request ();
+ break;
+
+ /* BRKRES Register */
+ case 0x00508:
+ s->brk = val & 0xff;
+ break;
+
+ /* UART Registers */
+ case 0x00900:
+ case 0x00908:
+ case 0x00910:
+ case 0x00918:
+ case 0x00920:
+ case 0x00928:
+ case 0x00930:
+ case 0x00938:
+ serial_mm_writeb(s->uart, addr, val);
+ break;
+
+ /* GPOUT Register */
+ case 0x00a00:
+ s->gpout = val & 0xff;
+ break;
+
+ /* I2COE Register */
+ case 0x00b08:
+ s->i2coe = val & 0x03;
+ break;
+
+ /* I2COUT Register */
+ case 0x00b10:
+ eeprom24c0x_write(val & 0x02, val & 0x01);
+ s->i2cout = val;
+ break;
+
+ /* I2CSEL Register */
+ case 0x00b18:
+ s->i2csel = val & 0x01;
+ break;
+
+ default:
+#if 0
+ printf ("malta_fpga_write: Bad register offset 0x" TARGET_FMT_lx "\n",
+ addr);
+#endif
+ break;
+ }
+}
+
+static CPUReadMemoryFunc *malta_fpga_read[] = {
+ malta_fpga_readl,
+ malta_fpga_readl,
+ malta_fpga_readl
+};
+
+static CPUWriteMemoryFunc *malta_fpga_write[] = {
+ malta_fpga_writel,
+ malta_fpga_writel,
+ malta_fpga_writel
+};
+
+void malta_fpga_reset(void *opaque)
+{
+ MaltaFPGAState *s = opaque;
+
+ s->leds = 0x00;
+ s->brk = 0x0a;
+ s->gpout = 0x00;
+ s->i2cin = 0x3;
+ s->i2coe = 0x0;
+ s->i2cout = 0x3;
+ s->i2csel = 0x1;
+
+ s->display_text[8] = '\0';
+ snprintf(s->display_text, 9, " ");
+ malta_fpga_update_display(s);
+}
+
+MaltaFPGAState *malta_fpga_init(target_phys_addr_t base, CPUState *env)
+{
+ MaltaFPGAState *s;
+ CharDriverState *uart_chr;
+ int malta;
+
+ s = (MaltaFPGAState *)qemu_mallocz(sizeof(MaltaFPGAState));
+
+ malta = cpu_register_io_memory(0, malta_fpga_read,
+ malta_fpga_write, s);
+
+ cpu_register_physical_memory(base, 0x100000, malta);
+
+ s->display = qemu_chr_open("vc");
+ qemu_chr_printf(s->display, "\e[HMalta LEDBAR\r\n");
+ qemu_chr_printf(s->display, "+--------+\r\n");
+ qemu_chr_printf(s->display, "+ +\r\n");
+ qemu_chr_printf(s->display, "+--------+\r\n");
+ qemu_chr_printf(s->display, "\n");
+ qemu_chr_printf(s->display, "Malta ASCII\r\n");
+ qemu_chr_printf(s->display, "+--------+\r\n");
+ qemu_chr_printf(s->display, "+ +\r\n");
+ qemu_chr_printf(s->display, "+--------+\r\n");
+
+ uart_chr = qemu_chr_open("vc");
+ qemu_chr_printf(uart_chr, "CBUS UART\r\n");
+ s->uart = serial_mm_init(base, 3, env->irq[2], uart_chr, 0);
+
+ malta_fpga_reset(s);
+ qemu_register_reset(malta_fpga_reset, s);
+
+ return s;
+}
+
+/* Audio support */
+#ifdef HAS_AUDIO
+static void audio_init (PCIBus *pci_bus)
+{
+ struct soundhw *c;
+ int audio_enabled = 0;
+
+ for (c = soundhw; !audio_enabled && c->name; ++c) {
+ audio_enabled = c->enabled;
+ }
+
+ if (audio_enabled) {
+ AudioState *s;
+
+ s = AUD_init ();
+ if (s) {
+ for (c = soundhw; c->name; ++c) {
+ if (c->enabled) {
+ if (c->isa) {
+ fprintf(stderr, "qemu: Unsupported Sound Card: %s\n", c->name);
+ exit(1);
+ }
+ else {
+ if (pci_bus) {
+ c->init.init_pci (pci_bus, s);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+#endif
+
+/* Network support */
+static void network_init (PCIBus *pci_bus)
+{
+ int i;
+ NICInfo *nd;
+
+ for(i = 0; i < nb_nics; i++) {
+ nd = &nd_table[i];
+ if (!nd->model) {
+ nd->model = "pcnet";
+ }
+ if (i == 0 && strcmp(nd->model, "pcnet") == 0) {
+ /* The malta board has a PCNet card using PCI SLOT 11 */
+ pci_nic_init(pci_bus, nd, 88);
+ } else {
+ pci_nic_init(pci_bus, nd, -1);
+ }
+ }
+}
+
+/* ROM and pseudo bootloader
+
+ The following code implements a very very simple bootloader. It first
+ loads the registers a0 to a3 to the values expected by the OS, and
+ then jump at the kernel address.
+
+ The bootloader should pass the locations of the kernel arguments and
+ environment variables tables. Those tables contain the 32-bit address
+ of NULL terminated strings. The environment variables table should be
+ terminated by a NULL address.
+
+ For a simpler implementation, the number of kernel arguments is fixed
+ to two (the name of the kernel and the command line), and the two
+ tables are actually the same one.
+
+ The registers a0 to a3 should contain the following values:
+ a0 - number of kernel arguments
+ a1 - 32-bit address of the kernel arguments table
+ a2 - 32-bit address of the environment variables table
+ a3 - RAM size in bytes
+*/
+
+static void write_bootloader (CPUState *env, unsigned long bios_offset, int64_t kernel_entry)
+{
+ uint32_t *p;
+
+ /* Small bootloader */
+ p = (uint32_t *) (phys_ram_base + bios_offset);
+ stl_raw(p++, 0x0bf00160); /* j 0x1fc00580 */
+ stl_raw(p++, 0x00000000); /* nop */
+
+ /* YAMON service vector */
+ stl_raw(phys_ram_base + bios_offset + 0x500, 0xbfc00580); /* start: */
+ stl_raw(phys_ram_base + bios_offset + 0x504, 0xbfc0083c); /* print_count: */
+ stl_raw(phys_ram_base + bios_offset + 0x520, 0xbfc00580); /* start: */
+ stl_raw(phys_ram_base + bios_offset + 0x52c, 0xbfc00800); /* flush_cache: */
+ stl_raw(phys_ram_base + bios_offset + 0x534, 0xbfc00808); /* print: */
+ stl_raw(phys_ram_base + bios_offset + 0x538, 0xbfc00800); /* reg_cpu_isr: */
+ stl_raw(phys_ram_base + bios_offset + 0x53c, 0xbfc00800); /* unred_cpu_isr: */
+ stl_raw(phys_ram_base + bios_offset + 0x540, 0xbfc00800); /* reg_ic_isr: */
+ stl_raw(phys_ram_base + bios_offset + 0x544, 0xbfc00800); /* unred_ic_isr: */
+ stl_raw(phys_ram_base + bios_offset + 0x548, 0xbfc00800); /* reg_esr: */
+ stl_raw(phys_ram_base + bios_offset + 0x54c, 0xbfc00800); /* unreg_esr: */
+ stl_raw(phys_ram_base + bios_offset + 0x550, 0xbfc00800); /* getchar: */
+ stl_raw(phys_ram_base + bios_offset + 0x554, 0xbfc00800); /* syscon_read: */
+
+
+ /* Second part of the bootloader */
+ p = (uint32_t *) (phys_ram_base + bios_offset + 0x580);
+ stl_raw(p++, 0x24040002); /* addiu a0, zero, 2 */
+ stl_raw(p++, 0x3c1d0000 | (((ENVP_ADDR - 64) >> 16) & 0xffff)); /* lui sp, high(ENVP_ADDR) */
+ stl_raw(p++, 0x37bd0000 | ((ENVP_ADDR - 64) & 0xffff)); /* ori sp, a0, low(ENVP_ADDR) */
+ stl_raw(p++, 0x3c050000 | ((ENVP_ADDR >> 16) & 0xffff)); /* lui a1, high(ENVP_ADDR) */
+ stl_raw(p++, 0x34a50000 | (ENVP_ADDR & 0xffff)); /* ori a1, a0, low(ENVP_ADDR) */
+ stl_raw(p++, 0x3c060000 | (((ENVP_ADDR + 8) >> 16) & 0xffff)); /* lui a2, high(ENVP_ADDR + 8) */
+ stl_raw(p++, 0x34c60000 | ((ENVP_ADDR + 8) & 0xffff)); /* ori a2, a2, low(ENVP_ADDR + 8) */
+ stl_raw(p++, 0x3c070000 | (env->ram_size >> 16)); /* lui a3, high(env->ram_size) */
+ stl_raw(p++, 0x34e70000 | (env->ram_size & 0xffff)); /* ori a3, a3, low(env->ram_size) */
+
+ /* Load BAR registers as done by YAMON */
+ stl_raw(p++, 0x3c09bbe0); /* lui t1, 0xbbe0 */
+
+#ifdef TARGET_WORDS_BIGENDIAN
+ stl_raw(p++, 0x3c08c000); /* lui t0, 0xc000 */
+#else
+ stl_raw(p++, 0x340800c0); /* ori t0, r0, 0x00c0 */
+#endif
+ stl_raw(p++, 0xad280048); /* sw t0, 0x0048(t1) */
+#ifdef TARGET_WORDS_BIGENDIAN
+ stl_raw(p++, 0x3c084000); /* lui t0, 0x4000 */
+#else
+ stl_raw(p++, 0x34080040); /* ori t0, r0, 0x0040 */
+#endif
+ stl_raw(p++, 0xad280050); /* sw t0, 0x0050(t1) */
+
+#ifdef TARGET_WORDS_BIGENDIAN
+ stl_raw(p++, 0x3c088000); /* lui t0, 0x8000 */
+#else
+ stl_raw(p++, 0x34080080); /* ori t0, r0, 0x0080 */
+#endif
+ stl_raw(p++, 0xad280058); /* sw t0, 0x0058(t1) */
+#ifdef TARGET_WORDS_BIGENDIAN
+ stl_raw(p++, 0x3c083f00); /* lui t0, 0x3f00 */
+#else
+ stl_raw(p++, 0x3408003f); /* ori t0, r0, 0x003f */
+#endif
+ stl_raw(p++, 0xad280060); /* sw t0, 0x0060(t1) */
+
+#ifdef TARGET_WORDS_BIGENDIAN
+ stl_raw(p++, 0x3c08c100); /* lui t0, 0xc100 */
+#else
+ stl_raw(p++, 0x340800c1); /* ori t0, r0, 0x00c1 */
+#endif
+ stl_raw(p++, 0xad280080); /* sw t0, 0x0080(t1) */
+#ifdef TARGET_WORDS_BIGENDIAN
+ stl_raw(p++, 0x3c085e00); /* lui t0, 0x5e00 */
+#else
+ stl_raw(p++, 0x3408005e); /* ori t0, r0, 0x005e */
+#endif
+ stl_raw(p++, 0xad280088); /* sw t0, 0x0088(t1) */
+
+ /* Jump to kernel code */
+ stl_raw(p++, 0x3c1f0000 | ((kernel_entry >> 16) & 0xffff)); /* lui ra, high(kernel_entry) */
+ stl_raw(p++, 0x37ff0000 | (kernel_entry & 0xffff)); /* ori ra, ra, low(kernel_entry) */
+ stl_raw(p++, 0x03e00008); /* jr ra */
+ stl_raw(p++, 0x00000000); /* nop */
+
+ /* YAMON subroutines */
+ p = (uint32_t *) (phys_ram_base + bios_offset + 0x800);
+ stl_raw(p++, 0x03e00008); /* jr ra */
+ stl_raw(p++, 0x24020000); /* li v0,0 */
+ /* 808 YAMON print */
+ stl_raw(p++, 0x03e06821); /* move t5,ra */
+ stl_raw(p++, 0x00805821); /* move t3,a0 */
+ stl_raw(p++, 0x00a05021); /* move t2,a1 */
+ stl_raw(p++, 0x91440000); /* lbu a0,0(t2) */
+ stl_raw(p++, 0x254a0001); /* addiu t2,t2,1 */
+ stl_raw(p++, 0x10800005); /* beqz a0,834 */
+ stl_raw(p++, 0x00000000); /* nop */
+ stl_raw(p++, 0x0ff0021c); /* jal 870 */
+ stl_raw(p++, 0x00000000); /* nop */
+ stl_raw(p++, 0x08000205); /* j 814 */
+ stl_raw(p++, 0x00000000); /* nop */
+ stl_raw(p++, 0x01a00008); /* jr t5 */
+ stl_raw(p++, 0x01602021); /* move a0,t3 */
+ /* 0x83c YAMON print_count */
+ stl_raw(p++, 0x03e06821); /* move t5,ra */
+ stl_raw(p++, 0x00805821); /* move t3,a0 */
+ stl_raw(p++, 0x00a05021); /* move t2,a1 */
+ stl_raw(p++, 0x00c06021); /* move t4,a2 */
+ stl_raw(p++, 0x91440000); /* lbu a0,0(t2) */
+ stl_raw(p++, 0x0ff0021c); /* jal 870 */
+ stl_raw(p++, 0x00000000); /* nop */
+ stl_raw(p++, 0x254a0001); /* addiu t2,t2,1 */
+ stl_raw(p++, 0x258cffff); /* addiu t4,t4,-1 */
+ stl_raw(p++, 0x1580fffa); /* bnez t4,84c */
+ stl_raw(p++, 0x00000000); /* nop */
+ stl_raw(p++, 0x01a00008); /* jr t5 */
+ stl_raw(p++, 0x01602021); /* move a0,t3 */
+ /* 0x870 */
+ stl_raw(p++, 0x3c08b800); /* lui t0,0xb400 */
+ stl_raw(p++, 0x350803f8); /* ori t0,t0,0x3f8 */
+ stl_raw(p++, 0x91090005); /* lbu t1,5(t0) */
+ stl_raw(p++, 0x00000000); /* nop */
+ stl_raw(p++, 0x31290040); /* andi t1,t1,0x40 */
+ stl_raw(p++, 0x1120fffc); /* beqz t1,878 <outch+0x8> */
+ stl_raw(p++, 0x00000000); /* nop */
+ stl_raw(p++, 0x03e00008); /* jr ra */
+ stl_raw(p++, 0xa1040000); /* sb a0,0(t0) */
+
+}
+
+static void prom_set(int index, const char *string, ...)
+{
+ va_list ap;
+ int32_t *p;
+ int32_t table_addr;
+ char *s;
+
+ if (index >= ENVP_NB_ENTRIES)
+ return;
+
+ p = (int32_t *) (phys_ram_base + ENVP_ADDR + VIRT_TO_PHYS_ADDEND);
+ p += index;
+
+ if (string == NULL) {
+ stl_raw(p, 0);
+ return;
+ }
+
+ table_addr = ENVP_ADDR + sizeof(int32_t) * ENVP_NB_ENTRIES + index * ENVP_ENTRY_SIZE;
+ s = (char *) (phys_ram_base + VIRT_TO_PHYS_ADDEND + table_addr);
+
+ stl_raw(p, table_addr);
+
+ va_start(ap, string);
+ vsnprintf (s, ENVP_ENTRY_SIZE, string, ap);
+ va_end(ap);
+}
+
+/* Kernel */
+static int64_t load_kernel (CPUState *env)
+{
+ int64_t kernel_entry, kernel_low, kernel_high;
+ int index = 0;
+ long initrd_size;
+ ram_addr_t initrd_offset;
+
+ if (load_elf(env->kernel_filename, VIRT_TO_PHYS_ADDEND,
+ &kernel_entry, &kernel_low, &kernel_high) < 0) {
+ fprintf(stderr, "qemu: could not load kernel '%s'\n",
+ env->kernel_filename);
+ exit(1);
+ }
+
+ /* load initrd */
+ initrd_size = 0;
+ initrd_offset = 0;
+ if (env->initrd_filename) {
+ initrd_size = get_image_size (env->initrd_filename);
+ if (initrd_size > 0) {
+ initrd_offset = (kernel_high + ~TARGET_PAGE_MASK) & TARGET_PAGE_MASK;
+ if (initrd_offset + initrd_size > env->ram_size) {
+ fprintf(stderr,
+ "qemu: memory too small for initial ram disk '%s'\n",
+ env->initrd_filename);
+ exit(1);
+ }
+ initrd_size = load_image(env->initrd_filename,
+ phys_ram_base + initrd_offset);
+ }
+ if (initrd_size == (target_ulong) -1) {
+ fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
+ env->initrd_filename);
+ exit(1);
+ }
+ }
+
+ /* Store command line. */
+ prom_set(index++, env->kernel_filename);
+ if (initrd_size > 0)
+ prom_set(index++, "rd_start=0x" TARGET_FMT_lx " rd_size=%li %s",
+ PHYS_TO_VIRT(initrd_offset), initrd_size,
+ env->kernel_cmdline);
+ else
+ prom_set(index++, env->kernel_cmdline);
+
+ /* Setup minimum environment variables */
+ prom_set(index++, "memsize");
+ prom_set(index++, "%i", env->ram_size);
+ prom_set(index++, "modetty0");
+ prom_set(index++, "38400n8r");
+ prom_set(index++, NULL);
+
+ return kernel_entry;
+}
+
+static void main_cpu_reset(void *opaque)
+{
+ CPUState *env = opaque;
+ cpu_reset(env);
+
+ /* The bootload does not need to be rewritten as it is located in a
+ read only location. The kernel location and the arguments table
+ location does not change. */
+ if (env->kernel_filename) {
+ env->CP0_Status &= ~((1 << CP0St_BEV) | (1 << CP0St_ERL));
+ load_kernel (env);
+ }
+}
+
+static
+void mips_malta_init (int ram_size, int vga_ram_size, int boot_device,
+ DisplayState *ds, const char **fd_filename, int snapshot,
+ const char *kernel_filename, const char *kernel_cmdline,
+ const char *initrd_filename, const char *cpu_model)
+{
+ char buf[1024];
+ unsigned long bios_offset;
+ int64_t kernel_entry;
+ PCIBus *pci_bus;
+ CPUState *env;
+ RTCState *rtc_state;
+ /* fdctrl_t *floppy_controller; */
+ MaltaFPGAState *malta_fpga;
+ int ret;
+ mips_def_t *def;
+ qemu_irq *i8259;
+
+ /* init CPUs */
+ if (cpu_model == NULL) {
+#ifdef TARGET_MIPS64
+ cpu_model = "R4000";
+#else
+ cpu_model = "24Kf";
+#endif
+ }
+ if (mips_find_by_name(cpu_model, &def) != 0)
+ def = NULL;
+ env = cpu_init();
+ cpu_mips_register(env, def);
+ register_savevm("cpu", 0, 3, cpu_save, cpu_load, env);
+ qemu_register_reset(main_cpu_reset, env);
+
+ /* allocate RAM */
+ cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
+
+ /* Map the bios at two physical locations, as on the real board */
+ bios_offset = ram_size + vga_ram_size;
+ cpu_register_physical_memory(0x1e000000LL,
+ BIOS_SIZE, bios_offset | IO_MEM_ROM);
+ cpu_register_physical_memory(0x1fc00000LL,
+ BIOS_SIZE, bios_offset | IO_MEM_ROM);
+
+ /* Load a BIOS image except if a kernel image has been specified. In
+ the later case, just write a small bootloader to the flash
+ location. */
+ if (kernel_filename) {
+ env->ram_size = ram_size;
+ env->kernel_filename = kernel_filename;
+ env->kernel_cmdline = kernel_cmdline;
+ env->initrd_filename = initrd_filename;
+ kernel_entry = load_kernel(env);
+ env->CP0_Status &= ~((1 << CP0St_BEV) | (1 << CP0St_ERL));
+ write_bootloader(env, bios_offset, kernel_entry);
+ } else {
+ snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME);
+ ret = load_image(buf, phys_ram_base + bios_offset);
+ if (ret < 0 || ret > BIOS_SIZE) {
+ fprintf(stderr, "qemu: Warning, could not load MIPS bios '%s'\n",
+ buf);
+ exit(1);
+ }
+ }
+
+ /* Board ID = 0x420 (Malta Board with CoreLV)
+ XXX: theoretically 0x1e000010 should map to flash and 0x1fc00010 should
+ map to the board ID. */
+ stl_raw(phys_ram_base + bios_offset + 0x10, 0x00000420);
+
+ /* Init internal devices */
+ cpu_mips_irq_init_cpu(env);
+ cpu_mips_clock_init(env);
+ cpu_mips_irqctrl_init();
+
+ /* FPGA */
+ malta_fpga = malta_fpga_init(0x1f000000LL, env);
+
+ /* Interrupt controller */
+ /* The 8259 is attached to the MIPS CPU INT0 pin, ie interrupt 2 */
+ i8259 = i8259_init(env->irq[2]);
+
+ /* Northbridge */
+ pci_bus = pci_gt64120_init(i8259);
+
+ /* Southbridge */
+ piix4_init(pci_bus, 80);
+ pci_piix3_ide_init(pci_bus, bs_table, 81, i8259);
+ usb_uhci_init(pci_bus, 82);
+ piix4_pm_init(pci_bus, 83);
+ pit = pit_init(0x40, i8259[0]);
+ DMA_init(0);
+
+ /* Super I/O */
+ i8042_init(i8259[1], i8259[12], 0x60);
+ rtc_state = rtc_init(0x70, i8259[8]);
+ if (serial_hds[0])
+ serial_init(0x3f8, i8259[4], serial_hds[0]);
+ if (serial_hds[1])
+ serial_init(0x2f8, i8259[3], serial_hds[1]);
+ if (parallel_hds[0])
+ parallel_init(0x378, i8259[7], parallel_hds[0]);
+ /* XXX: The floppy controller does not work correctly, something is
+ probably wrong.
+ floppy_controller = fdctrl_init(i8259[6], 2, 0, 0x3f0, fd_table); */
+
+ /* Sound card */
+#ifdef HAS_AUDIO
+ audio_init(pci_bus);
+#endif
+
+ /* Network card */
+ network_init(pci_bus);
+
+ /* Optional PCI video card */
+ pci_cirrus_vga_init(pci_bus, ds, phys_ram_base + ram_size,
+ ram_size, vga_ram_size);
+}
+
+QEMUMachine mips_malta_machine = {
+ "malta",
+ "MIPS Malta Core LV",
+ mips_malta_init,
+};
Added: trunk/src/host/qemu-neo1973/hw/mips_pica61.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/mips_pica61.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/mips_pica61.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,179 @@
+/*
+ * QEMU Malta board support
+ *
+ * Copyright (c) 2007 Hervé Poussineau
+ *
+ * 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 "vl.h"
+
+#ifdef TARGET_WORDS_BIGENDIAN
+#define BIOS_FILENAME "mips_bios.bin"
+#else
+#define BIOS_FILENAME "mipsel_bios.bin"
+#endif
+
+#ifdef TARGET_MIPS64
+#define PHYS_TO_VIRT(x) ((x) | ~0x7fffffffULL)
+#else
+#define PHYS_TO_VIRT(x) ((x) | ~0x7fffffffU)
+#endif
+
+#define VIRT_TO_PHYS_ADDEND (-((int64_t)(int32_t)0x80000000))
+
+static const int ide_iobase[2] = { 0x1f0, 0x170 };
+static const int ide_iobase2[2] = { 0x3f6, 0x376 };
+static const int ide_irq[2] = { 14, 15 };
+
+static uint32_t serial_base[MAX_SERIAL_PORTS] = { 0x80006000, 0x80007000 };
+static int serial_irq[MAX_SERIAL_PORTS] = { 8, 9 };
+
+extern FILE *logfile;
+
+static void main_cpu_reset(void *opaque)
+{
+ CPUState *env = opaque;
+ cpu_reset(env);
+}
+
+static
+void mips_pica61_init (int ram_size, int vga_ram_size, int boot_device,
+ DisplayState *ds, const char **fd_filename, int snapshot,
+ const char *kernel_filename, const char *kernel_cmdline,
+ const char *initrd_filename, const char *cpu_model)
+{
+ char buf[1024];
+ unsigned long bios_offset;
+ int bios_size;
+ CPUState *env;
+ int i;
+ mips_def_t *def;
+ int available_ram;
+ qemu_irq *i8259;
+
+ /* init CPUs */
+ if (cpu_model == NULL) {
+#ifdef TARGET_MIPS64
+ cpu_model = "R4000";
+#else
+ /* FIXME: All wrong, this maybe should be R3000 for the older PICAs. */
+ cpu_model = "24Kf";
+#endif
+ }
+ if (mips_find_by_name(cpu_model, &def) != 0)
+ def = NULL;
+ env = cpu_init();
+ cpu_mips_register(env, def);
+ register_savevm("cpu", 0, 3, cpu_save, cpu_load, env);
+ qemu_register_reset(main_cpu_reset, env);
+
+ /* allocate RAM (limited to 256 MB) */
+ if (ram_size < 256 * 1024 * 1024)
+ available_ram = ram_size;
+ else
+ available_ram = 256 * 1024 * 1024;
+ cpu_register_physical_memory(0, available_ram, IO_MEM_RAM);
+
+ /* load a BIOS image */
+ bios_offset = ram_size + vga_ram_size;
+ snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME);
+ bios_size = load_image(buf, phys_ram_base + bios_offset);
+ if ((bios_size <= 0) || (bios_size > BIOS_SIZE)) {
+ /* fatal */
+ fprintf(stderr, "qemu: Error, could not load MIPS bios '%s'\n",
+ buf);
+ exit(1);
+ }
+ cpu_register_physical_memory(0x1fc00000,
+ BIOS_SIZE, bios_offset | IO_MEM_ROM);
+
+ /* Device map
+ *
+ * addr 0xe0004000: mc146818
+ * addr 0xe0005000 intr 6: ps2 keyboard
+ * addr 0xe0005000 intr 7: ps2 mouse
+ * addr 0xe0006000 intr 8: ns16550a,
+ * addr 0xe0007000 intr 9: ns16550a
+ * isa_io_base 0xe2000000 isa_mem_base 0xe3000000
+ */
+
+ /* Init CPU internal devices */
+ cpu_mips_irq_init_cpu(env);
+ cpu_mips_clock_init(env);
+ cpu_mips_irqctrl_init();
+
+ /* Register 64 KB of ISA IO space at 0x10000000 */
+ isa_mmio_init(0x10000000, 0x00010000);
+ isa_mem_base = 0x11000000;
+
+ /* PC style IRQ (i8259/i8254) and DMA (i8257) */
+ /* The PIC is attached to the MIPS CPU INT0 pin */
+ i8259 = i8259_init(env->irq[2]);
+ rtc_mm_init(0x80004070, 1, i8259[14]);
+ pit_init(0x40, 0);
+
+ /* Keyboard (i8042) */
+ i8042_mm_init(i8259[6], i8259[7], 0x80005060, 0);
+
+ /* IDE controller */
+ for(i = 0; i < 2; i++)
+ isa_ide_init(ide_iobase[i], ide_iobase2[i], i8259[ide_irq[i]],
+ bs_table[2 * i], bs_table[2 * i + 1]);
+
+ /* Network controller */
+ /* FIXME: missing NS SONIC DP83932 */
+
+ /* SCSI adapter */
+ /* FIXME: missing NCR 53C94 */
+
+ /* ISA devices (floppy, serial, parallel) */
+ fdctrl_init(i8259[1], 1, 1, 0x80003000, fd_table);
+ for(i = 0; i < MAX_SERIAL_PORTS; i++) {
+ if (serial_hds[i]) {
+ serial_mm_init(serial_base[i], 0, i8259[serial_irq[i]], serial_hds[i], 1);
+ }
+ }
+ for (i = 0; i < MAX_PARALLEL_PORTS; i++) {
+ if (parallel_hds[i]) {
+ /* FIXME: memory mapped! parallel_init(0x80008000, i8259[17], parallel_hds[i]); */
+ }
+ }
+
+ /* Sound card */
+ /* FIXME: missing Jazz sound, IRQ 18 */
+
+ /* LED indicator */
+ /* FIXME: missing LED indicator */
+
+ /* NVRAM */
+ ds1225y_init(0x80009000, "nvram");
+
+ /* Video card */
+ /* FIXME: This card is not the real one which was in the original PICA,
+ * but let's do with what Qemu currenly emulates... */
+ isa_vga_mm_init(ds, phys_ram_base + ram_size, ram_size, vga_ram_size,
+ 0x40000000, 0x60000000, 0);
+}
+
+QEMUMachine mips_pica61_machine = {
+ "pica61",
+ "Acer Pica 61",
+ mips_pica61_init,
+};
Modified: trunk/src/host/qemu-neo1973/hw/mips_r4k.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/mips_r4k.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/mips_r4k.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -14,11 +14,11 @@
#else
#define BIOS_FILENAME "mipsel_bios.bin"
#endif
-//#define BIOS_FILENAME "system.bin"
-#ifdef MIPS_HAS_MIPS64
-#define INITRD_LOAD_ADDR (int64_t)(int32_t)0x80800000
+
+#ifdef TARGET_MIPS64
+#define PHYS_TO_VIRT(x) ((x) | ~0x7fffffffULL)
#else
-#define INITRD_LOAD_ADDR (int32_t)0x80800000
+#define PHYS_TO_VIRT(x) ((x) | ~0x7fffffffU)
#endif
#define VIRT_TO_PHYS_ADDEND (-((int64_t)(int32_t)0x80000000))
@@ -35,18 +35,6 @@
static PITState *pit; /* PIT i8254 */
/*i8254 PIT is attached to the IRQ0 at PIC i8259 */
-/*The PIC is attached to the MIPS CPU INT0 pin */
-static void pic_irq_request(void *opaque, int level)
-{
- CPUState *env = first_cpu;
- if (level) {
- env->CP0_Cause |= 0x00000400;
- cpu_interrupt(env, CPU_INTERRUPT_HARD);
- } else {
- env->CP0_Cause &= ~0x00000400;
- cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
- }
-}
static void mips_qemu_writel (void *opaque, target_phys_addr_t addr,
uint32_t val)
@@ -80,10 +68,12 @@
const char *kernel_cmdline,
const char *initrd_filename)
{
- int64_t entry = 0;
+ int64_t entry, kernel_low, kernel_high;
long kernel_size, initrd_size;
+ ram_addr_t initrd_offset;
- kernel_size = load_elf(kernel_filename, VIRT_TO_PHYS_ADDEND, &entry);
+ kernel_size = load_elf(kernel_filename, VIRT_TO_PHYS_ADDEND,
+ &entry, &kernel_low, &kernel_high);
if (kernel_size >= 0) {
if ((entry & ~0x7fffffffULL) == 0x80000000)
entry = (int32_t)entry;
@@ -96,9 +86,20 @@
/* load initrd */
initrd_size = 0;
+ initrd_offset = 0;
if (initrd_filename) {
- initrd_size = load_image(initrd_filename,
- phys_ram_base + INITRD_LOAD_ADDR + VIRT_TO_PHYS_ADDEND);
+ initrd_size = get_image_size (initrd_filename);
+ if (initrd_size > 0) {
+ initrd_offset = (kernel_high + ~TARGET_PAGE_MASK) & TARGET_PAGE_MASK;
+ if (initrd_offset + initrd_size > ram_size) {
+ fprintf(stderr,
+ "qemu: memory too small for initial ram disk '%s'\n",
+ initrd_filename);
+ exit(1);
+ }
+ initrd_size = load_image(initrd_filename,
+ phys_ram_base + initrd_offset);
+ }
if (initrd_size == (target_ulong) -1) {
fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
initrd_filename);
@@ -110,8 +111,8 @@
if (initrd_size > 0) {
int ret;
ret = sprintf(phys_ram_base + (16 << 20) - 256,
- "rd_start=0x" TLSZ " rd_size=%li ",
- INITRD_LOAD_ADDR,
+ "rd_start=0x" TARGET_FMT_lx " rd_size=%li ",
+ PHYS_TO_VIRT((uint32_t)initrd_offset),
initrd_size);
strcpy (phys_ram_base + (16 << 20) - 256 + ret, kernel_cmdline);
}
@@ -119,8 +120,8 @@
strcpy (phys_ram_base + (16 << 20) - 256, kernel_cmdline);
}
- *(int *)(phys_ram_base + (16 << 20) - 260) = tswap32 (0x12345678);
- *(int *)(phys_ram_base + (16 << 20) - 264) = tswap32 (ram_size);
+ *(int32_t *)(phys_ram_base + (16 << 20) - 260) = tswap32 (0x12345678);
+ *(int32_t *)(phys_ram_base + (16 << 20) - 264) = tswap32 (ram_size);
}
static void main_cpu_reset(void *opaque)
@@ -133,19 +134,33 @@
env->kernel_cmdline, env->initrd_filename);
}
+static
void mips_r4k_init (int ram_size, int vga_ram_size, int boot_device,
DisplayState *ds, const char **fd_filename, int snapshot,
const char *kernel_filename, const char *kernel_cmdline,
- const char *initrd_filename)
+ const char *initrd_filename, const char *cpu_model)
{
char buf[1024];
unsigned long bios_offset;
int bios_size;
CPUState *env;
- static RTCState *rtc_state;
+ RTCState *rtc_state;
int i;
+ mips_def_t *def;
+ qemu_irq *i8259;
+ /* init CPUs */
+ if (cpu_model == NULL) {
+#ifdef TARGET_MIPS64
+ cpu_model = "R4000";
+#else
+ cpu_model = "24Kf";
+#endif
+ }
+ if (mips_find_by_name(cpu_model, &def) != 0)
+ def = NULL;
env = cpu_init();
+ cpu_mips_register(env, def);
register_savevm("cpu", 0, 3, cpu_save, cpu_load, env);
qemu_register_reset(main_cpu_reset, env);
@@ -154,7 +169,7 @@
if (!mips_qemu_iomemtype) {
mips_qemu_iomemtype = cpu_register_io_memory(0, mips_qemu_read,
- mips_qemu_write, NULL);
+ mips_qemu_write, NULL);
}
cpu_register_physical_memory(0x1fbf0000, 0x10000, mips_qemu_iomemtype);
@@ -166,7 +181,7 @@
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME);
bios_size = load_image(buf, phys_ram_base + bios_offset);
if ((bios_size > 0) && (bios_size <= BIOS_SIZE)) {
- cpu_register_physical_memory((uint32_t)(0x1fc00000),
+ cpu_register_physical_memory(0x1fc00000,
BIOS_SIZE, bios_offset | IO_MEM_ROM);
} else {
/* not fatal */
@@ -184,22 +199,24 @@
}
/* Init CPU internal devices */
+ cpu_mips_irq_init_cpu(env);
cpu_mips_clock_init(env);
cpu_mips_irqctrl_init();
- rtc_state = rtc_init(0x70, 8);
+ /* The PIC is attached to the MIPS CPU INT0 pin */
+ i8259 = i8259_init(env->irq[2]);
+ rtc_state = rtc_init(0x70, i8259[8]);
+
/* Register 64 KB of ISA IO space at 0x14000000 */
isa_mmio_init(0x14000000, 0x00010000);
isa_mem_base = 0x10000000;
- isa_pic = pic_init(pic_irq_request, env);
- pit = pit_init(0x40, 0);
+ pit = pit_init(0x40, i8259[0]);
for(i = 0; i < MAX_SERIAL_PORTS; i++) {
if (serial_hds[i]) {
- serial_init(&pic_set_irq_new, isa_pic,
- serial_io[i], serial_irq[i], serial_hds[i]);
+ serial_init(serial_io[i], i8259[serial_irq[i]], serial_hds[i]);
}
}
@@ -209,7 +226,7 @@
if (nd_table[0].vlan) {
if (nd_table[0].model == NULL
|| strcmp(nd_table[0].model, "ne2k_isa") == 0) {
- isa_ne2000_init(0x300, 9, &nd_table[0]);
+ isa_ne2000_init(0x300, i8259[9], &nd_table[0]);
} else {
fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model);
exit (1);
@@ -217,8 +234,11 @@
}
for(i = 0; i < 2; i++)
- isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i],
+ isa_ide_init(ide_iobase[i], ide_iobase2[i], i8259[ide_irq[i]],
bs_table[2 * i], bs_table[2 * i + 1]);
+
+ i8042_init(i8259[1], i8259[12], 0x60);
+ ds1225y_init(0x9000, "nvram");
}
QEMUMachine mips_machine = {
Modified: trunk/src/host/qemu-neo1973/hw/mips_timer.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/mips_timer.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/mips_timer.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -10,7 +10,7 @@
static uint32_t seed = 0;
uint32_t idx;
seed = seed * 314159 + 1;
- idx = (seed >> 16) % (MIPS_TLB_NB - env->CP0_Wired) + env->CP0_Wired;
+ idx = (seed >> 16) % (env->nb_tlb - env->CP0_Wired) + env->CP0_Wired;
return idx;
}
@@ -22,11 +22,11 @@
100 * 1000 * 1000, ticks_per_sec);
}
-static void cpu_mips_update_count (CPUState *env, uint32_t count,
- uint32_t compare)
+void cpu_mips_store_count (CPUState *env, uint32_t count)
{
uint64_t now, next;
uint32_t tmp;
+ uint32_t compare = env->CP0_Compare;
tmp = count;
if (count == compare)
@@ -49,16 +49,21 @@
qemu_mod_timer(env->timer, next);
}
-void cpu_mips_store_count (CPUState *env, uint32_t value)
+static void cpu_mips_update_count (CPUState *env, uint32_t count)
{
- cpu_mips_update_count(env, value, env->CP0_Compare);
+ if (env->CP0_Cause & (1 << CP0Ca_DC))
+ return;
+
+ cpu_mips_store_count(env, count);
}
void cpu_mips_store_compare (CPUState *env, uint32_t value)
{
- cpu_mips_update_count(env, cpu_mips_get_count(env), value);
- env->CP0_Cause &= ~0x00008000;
- cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+ env->CP0_Compare = value;
+ cpu_mips_update_count(env, cpu_mips_get_count(env));
+ if ((env->CP0_Config0 & (0x7 << CP0C0_AR)) == (1 << CP0C0_AR))
+ env->CP0_Cause &= ~(1 << CP0Ca_TI);
+ qemu_irq_lower(env->irq[7]);
}
static void mips_timer_cb (void *opaque)
@@ -71,15 +76,15 @@
fprintf(logfile, "%s\n", __func__);
}
#endif
- cpu_mips_update_count(env, cpu_mips_get_count(env), env->CP0_Compare);
- env->CP0_Cause |= 0x00008000;
- cpu_interrupt(env, CPU_INTERRUPT_HARD);
+ cpu_mips_update_count(env, cpu_mips_get_count(env));
+ if ((env->CP0_Config0 & (0x7 << CP0C0_AR)) == (1 << CP0C0_AR))
+ env->CP0_Cause |= 1 << CP0Ca_TI;
+ qemu_irq_raise(env->irq[7]);
}
void cpu_mips_clock_init (CPUState *env)
{
env->timer = qemu_new_timer(vm_clock, &mips_timer_cb, env);
env->CP0_Compare = 0;
- cpu_mips_update_count(env, 1, 0);
+ cpu_mips_update_count(env, 1);
}
-
Modified: trunk/src/host/qemu-neo1973/hw/modem.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/modem.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/modem.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -11,9 +11,6 @@
struct modem_s {
int enable;
CharDriverState chr;
- IOCanRWHandler *can_read;
- IOReadHandler *read;
- void *opaque;
int cmd_len;
char cmd[1024];
#define FIFO_LEN 4096
@@ -31,24 +28,15 @@
s->baud_delay = ticks_per_sec;
}
-static void modem_add_read_handler(CharDriverState *chr,
- IOCanRWHandler *modem_can_read, IOReadHandler *modem_read,
- void *opaque)
-{
- struct modem_s *s = (struct modem_s *) chr->opaque;
-
- s->can_read = modem_can_read;
- s->read = modem_read;
- s->opaque = opaque;
-}
-
static inline void modem_fifo_wake(struct modem_s *s)
{
if (!s->enable || !s->out_len)
return;
- if (s->can_read && s->can_read(s->opaque) && s->read) {
- s->read(s->opaque, s->outfifo + s->out_start ++, 1);
+ if (s->chr.chr_can_read && s->chr.chr_can_read(s->chr.handler_opaque) &&
+ s->chr.chr_read) {
+ s->chr.chr_read(s->chr.handler_opaque,
+ s->outfifo + s->out_start ++, 1);
s->out_len --;
s->out_start &= FIFO_LEN - 1;
}
@@ -440,7 +428,6 @@
s->chr.opaque = s;
s->chr.chr_write = modem_write;
s->chr.chr_ioctl = modem_ioctl;
- s->chr.chr_add_read_handler = modem_add_read_handler;
s->out_tm = qemu_new_timer(vm_clock, modem_out_tick, s);
return &s->chr;
Modified: trunk/src/host/qemu-neo1973/hw/nand.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/nand.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/nand.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -6,7 +6,7 @@
* Copyright (c) 2006 Openedhand Ltd.
* Written by Andrzej Zaborowski <balrog at zabor.org>
*
- * This code is licensed under the GPLv2.
+ * This code is licensed under the GNU GPL v2.
*/
#ifndef NAND_IO
@@ -396,24 +396,14 @@
{
int pagesize;
struct nand_flash_s *s;
- BlockDriverState *bs = 0;
if (nand_flash_ids[chip_id].size == 0) {
cpu_abort(cpu_single_env, "%s: Unsupported NAND chip ID.\n",
__FUNCTION__);
}
- if (mtd_filename) {
- bs = bdrv_new("mtd");
- if (bdrv_open(bs, mtd_filename, snapshot ? BDRV_O_SNAPSHOT : 0) < 0 ||
- qemu_key_check(bs, mtd_filename)) {
- bdrv_delete(bs);
- bs = 0;
- }
- }
-
s = (struct nand_flash_s *) qemu_mallocz(sizeof(struct nand_flash_s));
- s->bdrv = bs;
+ s->bdrv = mtd_bdrv;
s->manf_id = manf_id;
s->chip_id = chip_id;
s->size = nand_flash_ids[s->chip_id].size << 20;
@@ -442,13 +432,13 @@
pagesize = 1 << s->oob_shift;
s->mem_oob = 1;
- if (bs && bdrv_getlength(bs) >=
+ if (s->bdrv && bdrv_getlength(s->bdrv) >=
(s->pages << s->page_shift) + (s->pages << s->oob_shift)) {
pagesize = 0;
s->mem_oob = 0;
}
- if (!bs)
+ if (!s->bdrv)
pagesize += 1 << s->page_shift;
if (pagesize)
s->storage = (uint8_t *) memset(qemu_malloc(s->pages * pagesize),
Modified: trunk/src/host/qemu-neo1973/hw/ne2000.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/ne2000.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/ne2000.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -136,7 +136,7 @@
uint8_t phys[6]; /* mac address */
uint8_t curpag;
uint8_t mult[8]; /* multicast mask array */
- int irq;
+ qemu_irq irq;
PCIDevice *pci_dev;
VLANClientState *vc;
uint8_t macaddr[6];
@@ -164,16 +164,10 @@
int isr;
isr = (s->isr & s->imr) & 0x7f;
#if defined(DEBUG_NE2000)
- printf("NE2000: Set IRQ line %d to %d (%02x %02x)\n",
- s->irq, isr ? 1 : 0, s->isr, s->imr);
+ printf("NE2000: Set IRQ to %d (%02x %02x)\n",
+ isr ? 1 : 0, s->isr, s->imr);
#endif
- if (s->irq == 16) {
- /* PCI irq */
- pci_set_irq(s->pci_dev, 0, (isr != 0));
- } else {
- /* ISA irq */
- pic_set_irq(s->irq, (isr != 0));
- }
+ qemu_set_irq(s->irq, (isr != 0));
}
#define POLYNOMIAL 0x04c11db6
@@ -206,7 +200,7 @@
index = s->curpag << 8;
boundary = s->boundary << 8;
- if (index <= boundary)
+ if (index < boundary)
avail = boundary - index;
else
avail = (s->stop - s->start) - (index - boundary);
@@ -647,6 +641,7 @@
static void ne2000_save(QEMUFile* f,void* opaque)
{
NE2000State* s=(NE2000State*)opaque;
+ int tmp;
if (s->pci_dev)
pci_device_save(s->pci_dev, f);
@@ -669,7 +664,8 @@
qemu_put_buffer(f, s->phys, 6);
qemu_put_8s(f, &s->curpag);
qemu_put_buffer(f, s->mult, 8);
- qemu_put_be32s(f, &s->irq);
+ tmp = 0;
+ qemu_put_be32s(f, &tmp); /* ignored, was irq */
qemu_put_buffer(f, s->mem, NE2000_MEM_SIZE);
}
@@ -677,6 +673,7 @@
{
NE2000State* s=(NE2000State*)opaque;
int ret;
+ int tmp;
if (version_id > 3)
return -EINVAL;
@@ -709,13 +706,13 @@
qemu_get_buffer(f, s->phys, 6);
qemu_get_8s(f, &s->curpag);
qemu_get_buffer(f, s->mult, 8);
- qemu_get_be32s(f, &s->irq);
+ qemu_get_be32s(f, &tmp); /* ignored */
qemu_get_buffer(f, s->mem, NE2000_MEM_SIZE);
return 0;
}
-void isa_ne2000_init(int base, int irq, NICInfo *nd)
+void isa_ne2000_init(int base, qemu_irq irq, NICInfo *nd)
{
NE2000State *s;
@@ -781,7 +778,7 @@
register_ioport_read(addr + 0x1f, 1, 1, ne2000_reset_ioport_read, s);
}
-void pci_ne2000_init(PCIBus *bus, NICInfo *nd)
+void pci_ne2000_init(PCIBus *bus, NICInfo *nd, int devfn)
{
PCINE2000State *d;
NE2000State *s;
@@ -789,7 +786,7 @@
d = (PCINE2000State *)pci_register_device(bus,
"NE2000", sizeof(PCINE2000State),
- -1,
+ devfn,
NULL, NULL);
pci_conf = d->dev.config;
pci_conf[0x00] = 0xec; // Realtek 8029
@@ -804,7 +801,7 @@
pci_register_io_region(&d->dev, 0, 0x100,
PCI_ADDRESS_SPACE_IO, ne2000_map);
s = &d->ne2000;
- s->irq = 16; // PCI interrupt
+ s->irq = d->dev.irq[0];
s->pci_dev = (PCIDevice *)d;
memcpy(s->macaddr, nd->macaddr, 6);
ne2000_reset(s);
Modified: trunk/src/host/qemu-neo1973/hw/neo1973.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/neo1973.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/neo1973.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -56,15 +56,15 @@
struct neo_board_s {
struct s3c_state_s *cpu;
- struct i2c_slave_s *pmu;
- struct i2c_slave_s *wm;
- struct i2c_slave_s *lcm;
+ i2c_slave *pmu;
+ i2c_slave *wm;
+ i2c_slave *lcm;
CharDriverState *modem;
- void *kbd_pic;
+ qemu_irq *kbd_pic;
};
/* Handlers for output ports */
-static void neo_bl_switch(int line, int level, void *opaque)
+static void neo_bl_switch(void *opaque, int line, int level)
{
neo_printf("LCD Backlight now %s.\n", level ? "on" : "off");
}
@@ -80,46 +80,46 @@
#endif
}
-static void neo_gpspwr_switch(int line, int level, void *opaque)
+static void neo_gpspwr_switch(void *opaque, int line, int level)
{
neo_printf("GPS powered %s.\n", level ? "up" : "down");
}
-static void neo_modem_rst_switch(int line, int level, void *opaque)
+static void neo_modem_rst_switch(void *opaque, int line, int level)
{
if (level)
neo_printf("Modem reset.\n");
}
-static void neo_modem_switch(int line, int level, void *opaque)
+static void neo_modem_switch(void *opaque, int line, int level)
{
struct neo_board_s *s = (struct neo_board_s *) opaque;
modem_enable(s->modem, level);
neo_printf("Modem powered %s.\n", level ? "up" : "down");
}
-static void neo_lcd_rst_switch(int line, int level, void *opaque)
+static void neo_lcd_rst_switch(void *opaque, int line, int level)
{
if (level)
neo_printf("LCD reset.\n");
}
-static void neo_vib_switch(int line, int level, void *opaque)
+static void neo_vib_switch(void *opaque, int line, int level)
{
neo_printf("%s.\n", level ? "Buzz, buzz" : "Vibrator stopped");
}
-static void neo_gsm_switch(int line, int level, void *opaque)
+static void neo_gsm_switch(void *opaque, int line, int level)
{
neo_printf("GSM %sabled.\n", level ? "dis" : "en");
}
-static void neo_bt_switch(int line, int level, void *opaque)
+static void neo_bt_switch(void *opaque, int line, int level)
{
neo_printf("Bluetooth transciever %sabled.\n", level ? "en" : "dis");
}
-static void neo_gps_switch(int line, int level, void *opaque)
+static void neo_gps_switch(void *opaque, int line, int level)
{
neo_printf("GPS %sV supply is now %s.\n",
#ifdef GTA01Bv3
@@ -130,19 +130,19 @@
level ? "on" : "off");
}
-static void neo_gps_rst_switch(int line, int level, void *opaque)
+static void neo_gps_rst_switch(void *opaque, int line, int level)
{
if (level)
neo_printf("GPS reset.\n");
}
/* Handlers for input ports */
-static void neo_mmc_cover_switch(void *pic, int in)
+static void neo_mmc_cover_switch(void *irq, int in)
{
- pic_set_irq_new(pic, GTA01_IRQ_nSD_DETECT, !in);
+ qemu_set_irq((qemu_irq) irq, !in);
}
-static void neo_mmc_writeprotect_switch(void *pic, int wp)
+static void neo_mmc_writeprotect_switch(void *irq, int wp)
{
}
@@ -152,10 +152,10 @@
struct neo_board_s *s = (struct neo_board_s *) opaque;
switch (keycode & 0x7f) {
case 0x1c: /* Return */
- pic_set_irq_new(s->kbd_pic, GTA01_IRQ_911_KEY, !(keycode & 0x80));
+ qemu_set_irq(s->kbd_pic[GTA01_IRQ_911_KEY], !(keycode & 0x80));
break;
case 0x39: /* Space */
- pic_set_irq_new(s->kbd_pic, GTA01_IRQ_HOLD_KEY, !(keycode & 0x80));
+ qemu_set_irq(s->kbd_pic[GTA01_IRQ_HOLD_KEY], !(keycode & 0x80));
pcf_onkey_set(s->pmu, !(keycode & 80)); /* Active LOW */
break;
}
@@ -163,45 +163,47 @@
static void neo_kbd_init(struct neo_board_s *s)
{
- s->kbd_pic = s->cpu->io;
+ s->kbd_pic = s3c_gpio_in_get(s->cpu->io);
qemu_add_kbd_event_handler(neo_kbd_handler, s);
}
static void neo_gpio_setup(struct neo_board_s *s)
{
- s3c_gpio_handler_set(s->cpu->io, GTA01_GPIO_BACKLIGHT,
- neo_bl_switch, s);
- s3c_gpio_handler_set(s->cpu->io, GTA01_GPIO_GPS_PWRON,
- neo_gpspwr_switch, s);
- s3c_gpio_handler_set(s->cpu->io, GTA01_GPIO_MODEM_RST,
- neo_modem_rst_switch, s);
- s3c_gpio_handler_set(s->cpu->io, GTA01_GPIO_MODEM_ON,
- neo_modem_switch, s);
- s3c_gpio_handler_set(s->cpu->io, GTA01_GPIO_LCD_RESET,
- neo_lcd_rst_switch, s);
- s3c_gpio_handler_set(s->cpu->io, GTA01_GPIO_VIBRATOR_ON,
- neo_vib_switch, s);
- s3c_gpio_handler_set(s->cpu->io, GTA01_GPIO_VIBRATOR_ON2,
- neo_vib_switch, s);
- s3c_gpio_handler_set(s->cpu->io, GTA01v3_GPIO_nGSM_EN,
- neo_gsm_switch, s);
- s3c_gpio_handler_set(s->cpu->io, GTA01Bv2_GPIO_nGSM_EN,
- neo_gsm_switch, s);
- s3c_gpio_handler_set(s->cpu->io, GTA01_GPIO_BT_EN,
- neo_bt_switch, s);
- s3c_gpio_handler_set(s->cpu->io, GTA01_GPIO_GPS_EN_2V8,
- neo_gps_switch, s);
- s3c_gpio_handler_set(s->cpu->io, GTA01_GPIO_GPS_EN_3V,
- neo_gps_switch, s);
- s3c_gpio_handler_set(s->cpu->io, GTA01_GPIO_GPS_EN_3V3,
- neo_gps_switch, s);
- s3c_gpio_handler_set(s->cpu->io, GTA01_GPIO_GPS_RESET,
- neo_gps_rst_switch, s);
+ s3c_gpio_out_set(s->cpu->io, GTA01_GPIO_BACKLIGHT,
+ *qemu_allocate_irqs(neo_bl_switch, s, 1));
+ s3c_gpio_out_set(s->cpu->io, GTA01_GPIO_GPS_PWRON,
+ *qemu_allocate_irqs(neo_gpspwr_switch, s, 1));
+ s3c_gpio_out_set(s->cpu->io, GTA01_GPIO_MODEM_RST,
+ *qemu_allocate_irqs(neo_modem_rst_switch, s, 1));
+ s3c_gpio_out_set(s->cpu->io, GTA01_GPIO_MODEM_ON,
+ *qemu_allocate_irqs(neo_modem_switch, s, 1));
+ s3c_gpio_out_set(s->cpu->io, GTA01_GPIO_LCD_RESET,
+ *qemu_allocate_irqs(neo_lcd_rst_switch, s, 1));
+ s3c_gpio_out_set(s->cpu->io, GTA01_GPIO_VIBRATOR_ON,
+ *qemu_allocate_irqs(neo_vib_switch, s, 1));
+ s3c_gpio_out_set(s->cpu->io, GTA01_GPIO_VIBRATOR_ON2,
+ *qemu_allocate_irqs(neo_vib_switch, s, 1));
+ s3c_gpio_out_set(s->cpu->io, GTA01v3_GPIO_nGSM_EN,
+ *qemu_allocate_irqs(neo_gsm_switch, s, 1));
+ s3c_gpio_out_set(s->cpu->io, GTA01Bv2_GPIO_nGSM_EN,
+ *qemu_allocate_irqs(neo_gsm_switch, s, 1));
+ s3c_gpio_out_set(s->cpu->io, GTA01_GPIO_BT_EN,
+ *qemu_allocate_irqs(neo_bt_switch, s, 1));
+ s3c_gpio_out_set(s->cpu->io, GTA01_GPIO_GPS_EN_2V8,
+ *qemu_allocate_irqs(neo_gps_switch, s, 1));
+ s3c_gpio_out_set(s->cpu->io, GTA01_GPIO_GPS_EN_3V,
+ *qemu_allocate_irqs(neo_gps_switch, s, 1));
+ s3c_gpio_out_set(s->cpu->io, GTA01_GPIO_GPS_EN_3V3,
+ *qemu_allocate_irqs(neo_gps_switch, s, 1));
+ s3c_gpio_out_set(s->cpu->io, GTA01_GPIO_GPS_RESET,
+ *qemu_allocate_irqs(neo_gps_rst_switch, s, 1));
s3c_timers_cmp_handler_set(s->cpu->timers, 0, neo_bl_intensity, s);
/* MMC/SD host */
- s3c_mmci_handlers(s->cpu->mmci, s->cpu->io, neo_mmc_writeprotect_switch,
+ s3c_mmci_handlers(s->cpu->mmci,
+ s3c_gpio_in_get(s->cpu->io)[GTA01_IRQ_nSD_DETECT],
+ neo_mmc_writeprotect_switch,
neo_mmc_cover_switch);
}
@@ -214,48 +216,47 @@
/* National Semiconductor LM4857 Boomer audio amplifier */
struct lm4857_s {
- int i2c_dir;
- struct i2c_slave_s i2c;
+ i2c_slave i2c;
uint8_t regs[4];
};
-void lm_reset(struct i2c_slave_s *i2c)
+void lm_reset(i2c_slave *i2c)
{
- struct lm4857_s *s = (struct lm4857_s *) i2c->opaque;
+ struct lm4857_s *s = (struct lm4857_s *) i2c;
memset(s->regs, 0, sizeof(s->regs));
}
-static void lm_start(void *opaque, int dir)
+static void lm_event(i2c_slave *i2c, enum i2c_event event)
{
- struct lm4857_s *s = (struct lm4857_s *) opaque;
- s->i2c_dir = dir;
}
-static int lm_tx(void *opaque, uint8_t *data, int len)
+static int lm_rx(i2c_slave *i2c)
{
- struct lm4857_s *s = (struct lm4857_s *) opaque;
+ return 0x00;
+}
+
+static int lm_tx(i2c_slave *i2c, uint8_t data)
+{
+ struct lm4857_s *s = (struct lm4857_s *) i2c;
int reg, value;
- if (s->i2c_dir)
- return 1;
- while (len --) {
- reg = *data >> 6;
- value = *(data ++) & 0x3f;
+ reg = data >> 6;
+ value = data & 0x3f;
- if ((reg == 1 || reg == 2) && ((s->regs[reg] ^ value) & (1 << 5)))
- printf("%s: 3D enhance %s.\n", __FUNCTION__,
- (value & (1 << 5)) ? "On" : "Off");
- s->regs[reg] = value;
- }
+ if ((reg == 1 || reg == 2) && ((s->regs[reg] ^ value) & (1 << 5)))
+ printf("%s: 3D enhance %s.\n", __FUNCTION__,
+ (value & (1 << 5)) ? "On" : "Off");
+ s->regs[reg] = value;
return 0;
}
-struct i2c_slave_s *lm4857_init()
+i2c_slave *lm4857_init(i2c_bus *bus)
{
- struct lm4857_s *s = qemu_mallocz(sizeof(struct lm4857_s));
- s->i2c.opaque = s;
- s->i2c.tx = lm_tx;
- s->i2c.start = lm_start;
+ struct lm4857_s *s = (struct lm4857_s *)
+ i2c_slave_init(bus, 0, sizeof(struct lm4857_s));
+ s->i2c.event = lm_event;
+ s->i2c.send = lm_tx;
+ s->i2c.recv = lm_rx;
lm_reset(&s->i2c);
@@ -269,34 +270,32 @@
static void neo_i2c_setup(struct neo_board_s *s)
{
- struct i2c_bus_s *bus = (struct i2c_bus_s *)
- qemu_mallocz(sizeof(struct i2c_bus_s));
+ /* Attach the CPU on one end of our I2C bus. */
+ i2c_bus *bus = s3c_i2c_bus(s->cpu->i2c);
#ifdef HAS_AUDIO
AudioState *audio;
#endif
- s->pmu = pcf5060x_init(s->cpu->pic, GTA01_IRQ_PCF50606, 0);
- s->lcm = lm4857_init();
-
- /* Attach the CPU on one end of our I2C bus. */
- i2c_master_attach(bus, s3c_i2c_master(s->cpu->i2c));
-
/* Attach a PCF50606 to the bus */
- i2c_slave_attach(bus, NEO_PMU_ADDR, s->pmu);
+ s->pmu = pcf5060x_init(bus,
+ s3c_gpio_in_get(s->cpu->io)[GTA01_IRQ_PCF50606], 0);
+ i2c_set_slave_address(s->pmu, NEO_PMU_ADDR);
/* Attach a LM4857 to the bus */
- i2c_slave_attach(bus, NEO_AMP_ADDR, s->lcm);
+ s->lcm = lm4857_init(bus);
+ i2c_set_slave_address(s->lcm, NEO_AMP_ADDR);
#ifdef HAS_AUDIO
audio = AUD_init();
if (!audio)
return;
- s->wm = wm8753_init(audio);
/* Attach a WM8750 to the bus */
- i2c_slave_attach(bus, NEO_WM_ADDR, s->wm);
+ s->wm = wm8753_init(bus, audio);
+ i2c_set_slave_address(s->wm, NEO_WM_ADDR);
+
/* .. and to the sound interface. */
- s->cpu->i2s->opaque = s->wm->opaque;
+ s->cpu->i2s->opaque = s->wm;
s->cpu->i2s->codec_out = wm8753_dac_dat;
s->cpu->i2s->codec_in = wm8753_adc_dat;
wm8753_data_req_set(s->wm, s->cpu->i2s->data_req, s->cpu->i2s);
@@ -329,23 +328,23 @@
static void neo_init(int ram_size, int vga_ram_size, int boot_device,
DisplayState *ds, const char **fd_filename, int snapshot,
const char *kernel_filename, const char *kernel_cmdline,
- const char *initrd_filename)
+ const char *initrd_filename, const char *cpu_model)
{
uint32_t neo_ram = 0x08000000;
struct neo_board_s *s = (struct neo_board_s *)
qemu_mallocz(sizeof(struct neo_board_s));
- s->cpu = s3c2410_init(ds);
-
- /* Setup memory */
- if (ram_size < neo_ram + s->cpu->free_ram_start) {
+ /* Setup CPU & memory */
+ if (ram_size < neo_ram + S3C_SRAM_SIZE) {
fprintf(stderr, "This platform requires %i bytes of memory\n",
- neo_ram + s->cpu->free_ram_start);
+ neo_ram + S3C_SRAM_SIZE);
exit(1);
}
- cpu_register_physical_memory(S3C_RAM_BASE, neo_ram,
- s->cpu->free_ram_start | IO_MEM_RAM);
- s->cpu->free_ram_start += neo_ram;
+ if (cpu_model && strcmp(cpu_model, "arm920t")) {
+ fprintf(stderr, "This platform requires an ARM920T core\n");
+ exit(2);
+ }
+ s->cpu = s3c2410_init(neo_ram, ds);
s3c_nand_register(s->cpu, nand_init(NAND_MFR_SAMSUNG, 0x76));
@@ -370,9 +369,9 @@
initrd_filename, 0x49e, S3C_RAM_BASE);
#else
load_image("u-boot.bin",
- phys_ram_base + S3C_SRAM_SIZE + 0x03f80000);
+ phys_ram_base + 0x03f80000);
load_image(kernel_filename,
- phys_ram_base + S3C_SRAM_SIZE + 0x02000000);
+ phys_ram_base + 0x02000000);
s->cpu->env->regs[15] = S3C_RAM_BASE | 0x03f80000;
#endif
Modified: trunk/src/host/qemu-neo1973/hw/openpic.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/openpic.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/openpic.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -159,10 +159,10 @@
uint32_t pcsr; /* CPU sensitivity register */
IRQ_queue_t raised;
IRQ_queue_t servicing;
- CPUState *env;
+ qemu_irq *irqs;
} IRQ_dst_t;
-struct openpic_t {
+typedef struct openpic_t {
PCIDevice pci_dev;
int mem_index;
/* Global registers */
@@ -170,6 +170,7 @@
uint32_t glbc; /* Global configuration register */
uint32_t micr; /* MPIC interrupt configuration register */
uint32_t veni; /* Vendor identification register */
+ uint32_t pint; /* Processor initialization register */
uint32_t spve; /* Spurious vector register */
uint32_t tifr; /* Timer frequency reporting register */
/* Source registers */
@@ -195,7 +196,9 @@
uint32_t mbr; /* Mailbox register */
} mailboxes[MAX_MAILBOXES];
#endif
-};
+ /* IRQ out is used when in bypass mode (not implemented) */
+ qemu_irq irq_out;
+} openpic_t;
static inline void IRQ_setbit (IRQ_queue_t *q, int n_IRQ)
{
@@ -254,19 +257,34 @@
priority = IPVP_PRIORITY(src->ipvp);
if (priority <= dst->pctp) {
/* Too low priority */
+ DPRINTF("%s: IRQ %d has too low priority on CPU %d\n",
+ __func__, n_IRQ, n_CPU);
return;
}
if (IRQ_testbit(&dst->raised, n_IRQ)) {
/* Interrupt miss */
+ DPRINTF("%s: IRQ %d was missed on CPU %d\n",
+ __func__, n_IRQ, n_CPU);
return;
}
set_bit(&src->ipvp, IPVP_ACTIVITY);
IRQ_setbit(&dst->raised, n_IRQ);
- if (priority > dst->raised.priority) {
- IRQ_get_next(opp, &dst->raised);
- DPRINTF("Raise CPU IRQ\n");
- cpu_interrupt(dst->env, CPU_INTERRUPT_HARD);
+ if (priority < dst->raised.priority) {
+ /* An higher priority IRQ is already raised */
+ DPRINTF("%s: IRQ %d is hidden by raised IRQ %d on CPU %d\n",
+ __func__, n_IRQ, dst->raised.next, n_CPU);
+ return;
}
+ IRQ_get_next(opp, &dst->raised);
+ if (IRQ_get_next(opp, &dst->servicing) != -1 &&
+ priority < dst->servicing.priority) {
+ DPRINTF("%s: IRQ %d is hidden by servicing IRQ %d on CPU %d\n",
+ __func__, n_IRQ, dst->servicing.next, n_CPU);
+ /* Already servicing a higher priority IRQ */
+ return;
+ }
+ DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n", n_CPU, n_IRQ);
+ qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_INT]);
}
/* update pic state because registers for n_IRQ have changed value */
@@ -279,27 +297,34 @@
if (!src->pending) {
/* no irq pending */
+ DPRINTF("%s: IRQ %d is not pending\n", __func__, n_IRQ);
return;
}
if (test_bit(&src->ipvp, IPVP_MASK)) {
/* Interrupt source is disabled */
+ DPRINTF("%s: IRQ %d is disabled\n", __func__, n_IRQ);
return;
}
if (IPVP_PRIORITY(src->ipvp) == 0) {
/* Priority set to zero */
+ DPRINTF("%s: IRQ %d has 0 priority\n", __func__, n_IRQ);
return;
}
if (test_bit(&src->ipvp, IPVP_ACTIVITY)) {
/* IRQ already active */
+ DPRINTF("%s: IRQ %d is already active\n", __func__, n_IRQ);
return;
}
if (src->ide == 0x00000000) {
/* No target */
+ DPRINTF("%s: IRQ %d has no target\n", __func__, n_IRQ);
return;
}
- if (!test_bit(&src->ipvp, IPVP_MODE) ||
- src->ide == (1 << src->last_cpu)) {
+ if (src->ide == (1 << src->last_cpu)) {
+ /* Only one CPU is allowed to receive this IRQ */
+ IRQ_local_pipe(opp, src->last_cpu, n_IRQ);
+ } else if (!test_bit(&src->ipvp, IPVP_MODE)) {
/* Directed delivery mode */
for (i = 0; i < opp->nb_cpus; i++) {
if (test_bit(&src->ide, i))
@@ -307,9 +332,8 @@
}
} else {
/* Distributed delivery mode */
- /* XXX: incorrect code */
- for (i = src->last_cpu; i < src->last_cpu; i++) {
- if (i == MAX_IRQ)
+ for (i = src->last_cpu + 1; i != src->last_cpu; i++) {
+ if (i == opp->nb_cpus)
i = 0;
if (test_bit(&src->ide, i)) {
IRQ_local_pipe(opp, i, n_IRQ);
@@ -320,7 +344,7 @@
}
}
-void openpic_set_irq(void *opaque, int n_IRQ, int level)
+static void openpic_set_irq(void *opaque, int n_IRQ, int level)
{
openpic_t *opp = opaque;
IRQ_src_t *src;
@@ -349,6 +373,7 @@
/* Initialise controller registers */
opp->frep = ((EXT_IRQ - 1) << 16) | ((MAX_CPU - 1) << 8) | VID;
opp->veni = VENI;
+ opp->pint = 0x00000000;
opp->spve = 0x000000FF;
opp->tifr = 0x003F7A00;
/* ? */
@@ -359,7 +384,7 @@
opp->src[i].ide = 0x00000000;
}
/* Initialise IRQ destinations */
- for (i = 0; i < opp->nb_cpus; i++) {
+ for (i = 0; i < MAX_CPU; i++) {
opp->dst[i].pctp = 0x0000000F;
opp->dst[i].pcsr = 0x00000000;
memset(&opp->dst[i].raised, 0, sizeof(IRQ_queue_t));
@@ -510,6 +535,8 @@
static void openpic_gbl_write (void *opaque, uint32_t addr, uint32_t val)
{
openpic_t *opp = opaque;
+ IRQ_dst_t *dst;
+ int idx;
DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
if (addr & 0xF)
@@ -529,11 +556,18 @@
case 0x80: /* VENI */
break;
case 0x90: /* PINT */
- /* XXX: Should be able to reset any CPU */
- if (val & 1) {
- DPRINTF("Reset CPU IRQ\n");
- // cpu_interrupt(first_cpu, CPU_INTERRUPT_RESET);
+ for (idx = 0; idx < opp->nb_cpus; idx++) {
+ if ((val & (1 << idx)) && !(opp->pint & (1 << idx))) {
+ DPRINTF("Raise OpenPIC RESET output for CPU %d\n", idx);
+ dst = &opp->dst[idx];
+ qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_RESET]);
+ } else if (!(val & (1 << idx)) && (opp->pint & (1 << idx))) {
+ DPRINTF("Lower OpenPIC RESET output for CPU %d\n", idx);
+ dst = &opp->dst[idx];
+ qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_RESET]);
+ }
}
+ opp->pint = val;
break;
#if MAX_IPI > 0
case 0xA0: /* IPI_IPVP */
@@ -734,7 +768,7 @@
openpic_t *opp = opaque;
IRQ_src_t *src;
IRQ_dst_t *dst;
- int idx, n_IRQ;
+ int idx, s_IRQ, n_IRQ;
DPRINTF("%s: addr %08x <= %08x\n", __func__, addr, val);
if (addr & 0xF)
@@ -769,21 +803,21 @@
break;
case 0xB0: /* PEOI */
DPRINTF("PEOI\n");
- n_IRQ = IRQ_get_next(opp, &dst->servicing);
- IRQ_resetbit(&dst->servicing, n_IRQ);
+ s_IRQ = IRQ_get_next(opp, &dst->servicing);
+ IRQ_resetbit(&dst->servicing, s_IRQ);
dst->servicing.next = -1;
- src = &opp->src[n_IRQ];
/* Set up next servicing IRQ */
- IRQ_get_next(opp, &dst->servicing);
- /* Check queued interrupts. */
- n_IRQ = IRQ_get_next(opp, &dst->raised);
- if (n_IRQ != -1) {
- src = &opp->src[n_IRQ];
- if (IPVP_PRIORITY(src->ipvp) > dst->servicing.priority) {
- DPRINTF("Raise CPU IRQ\n");
- cpu_interrupt(dst->env, CPU_INTERRUPT_HARD);
- }
- }
+ s_IRQ = IRQ_get_next(opp, &dst->servicing);
+ /* Check queued interrupts. */
+ n_IRQ = IRQ_get_next(opp, &dst->raised);
+ src = &opp->src[n_IRQ];
+ if (n_IRQ != -1 &&
+ (s_IRQ == -1 ||
+ IPVP_PRIORITY(src->ipvp) > dst->servicing.priority)) {
+ DPRINTF("Raise OpenPIC INT output cpu %d irq %d\n",
+ idx, n_IRQ);
+ qemu_irq_raise(dst->irqs[OPENPIC_OUTPUT_INT]);
+ }
break;
default:
break;
@@ -814,11 +848,13 @@
retval = idx;
break;
case 0xA0: /* PIAC */
+ DPRINTF("Lower OpenPIC INT output\n");
+ qemu_irq_lower(dst->irqs[OPENPIC_OUTPUT_INT]);
n_IRQ = IRQ_get_next(opp, &dst->raised);
DPRINTF("PIAC: irq=%d\n", n_IRQ);
if (n_IRQ == -1) {
/* No more interrupt pending */
- retval = opp->spve;
+ retval = IPVP_VECTOR(opp->spve);
} else {
src = &opp->src[n_IRQ];
if (!test_bit(&src->ipvp, IPVP_ACTIVITY) ||
@@ -963,8 +999,8 @@
#endif
}
-openpic_t *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus,
- CPUPPCState **envp)
+qemu_irq *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus,
+ qemu_irq **irqs, qemu_irq irq_out)
{
openpic_t *opp;
uint8_t *pci_conf;
@@ -994,7 +1030,6 @@
} else {
opp = qemu_mallocz(sizeof(openpic_t));
}
-
opp->mem_index = cpu_register_io_memory(0, openpic_read,
openpic_write, opp);
@@ -1019,9 +1054,11 @@
opp->src[i].type = IRQ_INTERNAL;
}
for (i = 0; i < nb_cpus; i++)
- opp->dst[i].env = envp[i];
+ opp->dst[i].irqs = irqs[i];
+ opp->irq_out = irq_out;
openpic_reset(opp);
if (pmem_index)
*pmem_index = opp->mem_index;
- return opp;
+
+ return qemu_allocate_irqs(openpic_set_irq, opp, MAX_IRQ);
}
Modified: trunk/src/host/qemu-neo1973/hw/parallel.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/parallel.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/parallel.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -2,6 +2,7 @@
* QEMU Parallel PORT emulation
*
* Copyright (c) 2003-2005 Fabrice Bellard
+ * Copyright (c) 2007 Marko Kohtala
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -25,6 +26,18 @@
//#define DEBUG_PARALLEL
+#ifdef DEBUG_PARALLEL
+#define pdebug(fmt, arg...) printf("pp: " fmt, ##arg)
+#else
+#define pdebug(fmt, arg...) ((void)0)
+#endif
+
+#define PARA_REG_DATA 0
+#define PARA_REG_STS 1
+#define PARA_REG_CTR 2
+#define PARA_REG_EPP_ADDR 3
+#define PARA_REG_EPP_DATA 4
+
/*
* These are the definitions for the Printer Status Register
*/
@@ -33,129 +46,362 @@
#define PARA_STS_PAPER 0x20 /* Out of paper */
#define PARA_STS_ONLINE 0x10 /* Online */
#define PARA_STS_ERROR 0x08 /* Error complement */
+#define PARA_STS_TMOUT 0x01 /* EPP timeout */
/*
* These are the definitions for the Printer Control Register
*/
+#define PARA_CTR_DIR 0x20 /* Direction (1=read, 0=write) */
#define PARA_CTR_INTEN 0x10 /* IRQ Enable */
#define PARA_CTR_SELECT 0x08 /* Select In complement */
#define PARA_CTR_INIT 0x04 /* Initialize Printer complement */
#define PARA_CTR_AUTOLF 0x02 /* Auto linefeed complement */
#define PARA_CTR_STROBE 0x01 /* Strobe complement */
+#define PARA_CTR_SIGNAL (PARA_CTR_SELECT|PARA_CTR_INIT|PARA_CTR_AUTOLF|PARA_CTR_STROBE)
+
struct ParallelState {
- uint8_t data;
- uint8_t status; /* read only register */
+ uint8_t dataw;
+ uint8_t datar;
+ uint8_t status;
uint8_t control;
- int irq;
+ qemu_irq irq;
int irq_pending;
CharDriverState *chr;
int hw_driver;
+ int epp_timeout;
+ uint32_t last_read_offset; /* For debugging */
};
static void parallel_update_irq(ParallelState *s)
{
if (s->irq_pending)
- pic_set_irq(s->irq, 1);
+ qemu_irq_raise(s->irq);
else
- pic_set_irq(s->irq, 0);
+ qemu_irq_lower(s->irq);
}
-static void parallel_ioport_write(void *opaque, uint32_t addr, uint32_t val)
+static void
+parallel_ioport_write_sw(void *opaque, uint32_t addr, uint32_t val)
{
ParallelState *s = opaque;
+ pdebug("write addr=0x%02x val=0x%02x\n", addr, val);
+
addr &= 7;
-#ifdef DEBUG_PARALLEL
- printf("parallel: write addr=0x%02x val=0x%02x\n", addr, val);
-#endif
switch(addr) {
- case 0:
- if (s->hw_driver) {
- s->data = val;
- qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_WRITE_DATA, &s->data);
- } else {
- s->data = val;
- parallel_update_irq(s);
- }
+ case PARA_REG_DATA:
+ s->dataw = val;
+ parallel_update_irq(s);
break;
- case 2:
- if (s->hw_driver) {
- s->control = val;
- qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_WRITE_CONTROL, &s->control);
- } else {
- if ((val & PARA_CTR_INIT) == 0 ) {
- s->status = PARA_STS_BUSY;
- s->status |= PARA_STS_ACK;
- s->status |= PARA_STS_ONLINE;
- s->status |= PARA_STS_ERROR;
- }
- else if (val & PARA_CTR_SELECT) {
- if (val & PARA_CTR_STROBE) {
- s->status &= ~PARA_STS_BUSY;
- if ((s->control & PARA_CTR_STROBE) == 0)
- qemu_chr_write(s->chr, &s->data, 1);
- } else {
- if (s->control & PARA_CTR_INTEN) {
- s->irq_pending = 1;
- }
- }
- }
- parallel_update_irq(s);
- s->control = val;
- }
+ case PARA_REG_CTR:
+ if ((val & PARA_CTR_INIT) == 0 ) {
+ s->status = PARA_STS_BUSY;
+ s->status |= PARA_STS_ACK;
+ s->status |= PARA_STS_ONLINE;
+ s->status |= PARA_STS_ERROR;
+ }
+ else if (val & PARA_CTR_SELECT) {
+ if (val & PARA_CTR_STROBE) {
+ s->status &= ~PARA_STS_BUSY;
+ if ((s->control & PARA_CTR_STROBE) == 0)
+ qemu_chr_write(s->chr, &s->dataw, 1);
+ } else {
+ if (s->control & PARA_CTR_INTEN) {
+ s->irq_pending = 1;
+ }
+ }
+ }
+ parallel_update_irq(s);
+ s->control = val;
break;
}
}
-static uint32_t parallel_ioport_read(void *opaque, uint32_t addr)
+static void parallel_ioport_write_hw(void *opaque, uint32_t addr, uint32_t val)
{
ParallelState *s = opaque;
+ uint8_t parm = val;
+
+ /* Sometimes programs do several writes for timing purposes on old
+ HW. Take care not to waste time on writes that do nothing. */
+
+ s->last_read_offset = ~0U;
+
+ addr &= 7;
+ switch(addr) {
+ case PARA_REG_DATA:
+ if (s->dataw == val)
+ return;
+ pdebug("wd%02x\n", val);
+ qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_WRITE_DATA, &parm);
+ s->dataw = val;
+ break;
+ case PARA_REG_STS:
+ pdebug("ws%02x\n", val);
+ if (val & PARA_STS_TMOUT)
+ s->epp_timeout = 0;
+ break;
+ case PARA_REG_CTR:
+ val |= 0xc0;
+ if (s->control == val)
+ return;
+ pdebug("wc%02x\n", val);
+ qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_WRITE_CONTROL, &parm);
+ s->control = val;
+ break;
+ case PARA_REG_EPP_ADDR:
+ if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != PARA_CTR_INIT)
+ /* Controls not correct for EPP address cycle, so do nothing */
+ pdebug("wa%02x s\n", val);
+ else {
+ struct ParallelIOArg ioarg = { .buffer = &parm, .count = 1 };
+ if (qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE_ADDR, &ioarg)) {
+ s->epp_timeout = 1;
+ pdebug("wa%02x t\n", val);
+ }
+ else
+ pdebug("wa%02x\n", val);
+ }
+ break;
+ case PARA_REG_EPP_DATA:
+ if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != PARA_CTR_INIT)
+ /* Controls not correct for EPP data cycle, so do nothing */
+ pdebug("we%02x s\n", val);
+ else {
+ struct ParallelIOArg ioarg = { .buffer = &parm, .count = 1 };
+ if (qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE, &ioarg)) {
+ s->epp_timeout = 1;
+ pdebug("we%02x t\n", val);
+ }
+ else
+ pdebug("we%02x\n", val);
+ }
+ break;
+ }
+}
+
+static void
+parallel_ioport_eppdata_write_hw2(void *opaque, uint32_t addr, uint32_t val)
+{
+ ParallelState *s = opaque;
+ uint16_t eppdata = cpu_to_le16(val);
+ int err;
+ struct ParallelIOArg ioarg = {
+ .buffer = &eppdata, .count = sizeof(eppdata)
+ };
+ if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != PARA_CTR_INIT) {
+ /* Controls not correct for EPP data cycle, so do nothing */
+ pdebug("we%04x s\n", val);
+ return;
+ }
+ err = qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE, &ioarg);
+ if (err) {
+ s->epp_timeout = 1;
+ pdebug("we%04x t\n", val);
+ }
+ else
+ pdebug("we%04x\n", val);
+}
+
+static void
+parallel_ioport_eppdata_write_hw4(void *opaque, uint32_t addr, uint32_t val)
+{
+ ParallelState *s = opaque;
+ uint32_t eppdata = cpu_to_le32(val);
+ int err;
+ struct ParallelIOArg ioarg = {
+ .buffer = &eppdata, .count = sizeof(eppdata)
+ };
+ if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != PARA_CTR_INIT) {
+ /* Controls not correct for EPP data cycle, so do nothing */
+ pdebug("we%08x s\n", val);
+ return;
+ }
+ err = qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_EPP_WRITE, &ioarg);
+ if (err) {
+ s->epp_timeout = 1;
+ pdebug("we%08x t\n", val);
+ }
+ else
+ pdebug("we%08x\n", val);
+}
+
+static uint32_t parallel_ioport_read_sw(void *opaque, uint32_t addr)
+{
+ ParallelState *s = opaque;
uint32_t ret = 0xff;
addr &= 7;
switch(addr) {
- case 0:
- if (s->hw_driver) {
- qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_READ_DATA, &s->data);
- }
- ret = s->data;
+ case PARA_REG_DATA:
+ if (s->control & PARA_CTR_DIR)
+ ret = s->datar;
+ else
+ ret = s->dataw;
break;
- case 1:
- if (s->hw_driver) {
- qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_READ_STATUS, &s->status);
- ret = s->status;
- } else {
- ret = s->status;
- s->irq_pending = 0;
- if ((s->status & PARA_STS_BUSY) == 0 && (s->control & PARA_CTR_STROBE) == 0) {
- /* XXX Fixme: wait 5 microseconds */
- if (s->status & PARA_STS_ACK)
- s->status &= ~PARA_STS_ACK;
- else {
- /* XXX Fixme: wait 5 microseconds */
- s->status |= PARA_STS_ACK;
- s->status |= PARA_STS_BUSY;
- }
- }
- parallel_update_irq(s);
- }
+ case PARA_REG_STS:
+ ret = s->status;
+ s->irq_pending = 0;
+ if ((s->status & PARA_STS_BUSY) == 0 && (s->control & PARA_CTR_STROBE) == 0) {
+ /* XXX Fixme: wait 5 microseconds */
+ if (s->status & PARA_STS_ACK)
+ s->status &= ~PARA_STS_ACK;
+ else {
+ /* XXX Fixme: wait 5 microseconds */
+ s->status |= PARA_STS_ACK;
+ s->status |= PARA_STS_BUSY;
+ }
+ }
+ parallel_update_irq(s);
break;
- case 2:
- if (s->hw_driver) {
- qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_READ_CONTROL, &s->control);
- }
+ case PARA_REG_CTR:
ret = s->control;
break;
}
-#ifdef DEBUG_PARALLEL
- printf("parallel: read addr=0x%02x val=0x%02x\n", addr, ret);
-#endif
+ pdebug("read addr=0x%02x val=0x%02x\n", addr, ret);
return ret;
}
+static uint32_t parallel_ioport_read_hw(void *opaque, uint32_t addr)
+{
+ ParallelState *s = opaque;
+ uint8_t ret = 0xff;
+ addr &= 7;
+ switch(addr) {
+ case PARA_REG_DATA:
+ qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_READ_DATA, &ret);
+ if (s->last_read_offset != addr || s->datar != ret)
+ pdebug("rd%02x\n", ret);
+ s->datar = ret;
+ break;
+ case PARA_REG_STS:
+ qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_READ_STATUS, &ret);
+ ret &= ~PARA_STS_TMOUT;
+ if (s->epp_timeout)
+ ret |= PARA_STS_TMOUT;
+ if (s->last_read_offset != addr || s->status != ret)
+ pdebug("rs%02x\n", ret);
+ s->status = ret;
+ break;
+ case PARA_REG_CTR:
+ /* s->control has some bits fixed to 1. It is zero only when
+ it has not been yet written to. */
+ if (s->control == 0) {
+ qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_READ_CONTROL, &ret);
+ if (s->last_read_offset != addr)
+ pdebug("rc%02x\n", ret);
+ s->control = ret;
+ }
+ else {
+ ret = s->control;
+ if (s->last_read_offset != addr)
+ pdebug("rc%02x\n", ret);
+ }
+ break;
+ case PARA_REG_EPP_ADDR:
+ if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != (PARA_CTR_DIR|PARA_CTR_INIT))
+ /* Controls not correct for EPP addr cycle, so do nothing */
+ pdebug("ra%02x s\n", ret);
+ else {
+ struct ParallelIOArg ioarg = { .buffer = &ret, .count = 1 };
+ if (qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ_ADDR, &ioarg)) {
+ s->epp_timeout = 1;
+ pdebug("ra%02x t\n", ret);
+ }
+ else
+ pdebug("ra%02x\n", ret);
+ }
+ break;
+ case PARA_REG_EPP_DATA:
+ if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != (PARA_CTR_DIR|PARA_CTR_INIT))
+ /* Controls not correct for EPP data cycle, so do nothing */
+ pdebug("re%02x s\n", ret);
+ else {
+ struct ParallelIOArg ioarg = { .buffer = &ret, .count = 1 };
+ if (qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ, &ioarg)) {
+ s->epp_timeout = 1;
+ pdebug("re%02x t\n", ret);
+ }
+ else
+ pdebug("re%02x\n", ret);
+ }
+ break;
+ }
+ s->last_read_offset = addr;
+ return ret;
+}
+
+static uint32_t
+parallel_ioport_eppdata_read_hw2(void *opaque, uint32_t addr)
+{
+ ParallelState *s = opaque;
+ uint32_t ret;
+ uint16_t eppdata = ~0;
+ int err;
+ struct ParallelIOArg ioarg = {
+ .buffer = &eppdata, .count = sizeof(eppdata)
+ };
+ if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != (PARA_CTR_DIR|PARA_CTR_INIT)) {
+ /* Controls not correct for EPP data cycle, so do nothing */
+ pdebug("re%04x s\n", eppdata);
+ return eppdata;
+ }
+ err = qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ, &ioarg);
+ ret = le16_to_cpu(eppdata);
+
+ if (err) {
+ s->epp_timeout = 1;
+ pdebug("re%04x t\n", ret);
+ }
+ else
+ pdebug("re%04x\n", ret);
+ return ret;
+}
+
+static uint32_t
+parallel_ioport_eppdata_read_hw4(void *opaque, uint32_t addr)
+{
+ ParallelState *s = opaque;
+ uint32_t ret;
+ uint32_t eppdata = ~0U;
+ int err;
+ struct ParallelIOArg ioarg = {
+ .buffer = &eppdata, .count = sizeof(eppdata)
+ };
+ if ((s->control & (PARA_CTR_DIR|PARA_CTR_SIGNAL)) != (PARA_CTR_DIR|PARA_CTR_INIT)) {
+ /* Controls not correct for EPP data cycle, so do nothing */
+ pdebug("re%08x s\n", eppdata);
+ return eppdata;
+ }
+ err = qemu_chr_ioctl(s->chr, CHR_IOCTL_PP_EPP_READ, &ioarg);
+ ret = le32_to_cpu(eppdata);
+
+ if (err) {
+ s->epp_timeout = 1;
+ pdebug("re%08x t\n", ret);
+ }
+ else
+ pdebug("re%08x\n", ret);
+ return ret;
+}
+
+static void parallel_ioport_ecp_write(void *opaque, uint32_t addr, uint32_t val)
+{
+ addr &= 7;
+ pdebug("wecp%d=%02x\n", addr, val);
+}
+
+static uint32_t parallel_ioport_ecp_read(void *opaque, uint32_t addr)
+{
+ uint8_t ret = 0xff;
+ addr &= 7;
+ pdebug("recp%d:%02x\n", addr, ret);
+ return ret;
+}
+
/* If fd is zero, it means that the parallel device uses the console */
-ParallelState *parallel_init(int base, int irq, CharDriverState *chr)
+ParallelState *parallel_init(int base, qemu_irq irq, CharDriverState *chr)
{
ParallelState *s;
uint8_t dummy;
@@ -163,21 +409,39 @@
s = qemu_mallocz(sizeof(ParallelState));
if (!s)
return NULL;
- s->chr = chr;
- s->hw_driver = 0;
- if (qemu_chr_ioctl(chr, CHR_IOCTL_PP_READ_STATUS, &dummy) == 0)
- s->hw_driver = 1;
-
- s->irq = irq;
- s->data = 0;
+ s->datar = ~0;
+ s->dataw = ~0;
s->status = PARA_STS_BUSY;
s->status |= PARA_STS_ACK;
s->status |= PARA_STS_ONLINE;
s->status |= PARA_STS_ERROR;
s->control = PARA_CTR_SELECT;
s->control |= PARA_CTR_INIT;
+ s->irq = irq;
+ s->irq_pending = 0;
+ s->chr = chr;
+ s->hw_driver = 0;
+ s->epp_timeout = 0;
+ s->last_read_offset = ~0U;
- register_ioport_write(base, 8, 1, parallel_ioport_write, s);
- register_ioport_read(base, 8, 1, parallel_ioport_read, s);
+ if (qemu_chr_ioctl(chr, CHR_IOCTL_PP_READ_STATUS, &dummy) == 0) {
+ s->hw_driver = 1;
+ s->status = dummy;
+ }
+
+ if (s->hw_driver) {
+ register_ioport_write(base, 8, 1, parallel_ioport_write_hw, s);
+ register_ioport_read(base, 8, 1, parallel_ioport_read_hw, s);
+ register_ioport_write(base+4, 1, 2, parallel_ioport_eppdata_write_hw2, s);
+ register_ioport_read(base+4, 1, 2, parallel_ioport_eppdata_read_hw2, s);
+ register_ioport_write(base+4, 1, 4, parallel_ioport_eppdata_write_hw4, s);
+ register_ioport_read(base+4, 1, 4, parallel_ioport_eppdata_read_hw4, s);
+ register_ioport_write(base+0x400, 8, 1, parallel_ioport_ecp_write, s);
+ register_ioport_read(base+0x400, 8, 1, parallel_ioport_ecp_read, s);
+ }
+ else {
+ register_ioport_write(base, 8, 1, parallel_ioport_write_sw, s);
+ register_ioport_read(base, 8, 1, parallel_ioport_read_sw, s);
+ }
return s;
}
Modified: trunk/src/host/qemu-neo1973/hw/pc.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/pc.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/pc.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -32,9 +32,11 @@
#define LINUX_BOOT_FILENAME "linux_boot.bin"
#define KERNEL_LOAD_ADDR 0x00100000
-#define INITRD_LOAD_ADDR 0x00600000
+#define MAX_INITRD_LOAD_ADDR 0x38000000
#define KERNEL_PARAMS_ADDR 0x00090000
#define KERNEL_CMDLINE_ADDR 0x00099000
+/* Leave a chunk of memory at the top of RAM for the BIOS ACPI tables. */
+#define ACPI_DATA_SIZE 0x10000
static fdctrl_t *floppy_controller;
static RTCState *rtc_state;
@@ -47,15 +49,16 @@
}
/* MSDOS compatibility mode FPU exception support */
+static qemu_irq ferr_irq;
/* XXX: add IGNNE support */
void cpu_set_ferr(CPUX86State *s)
{
- pic_set_irq(13, 1);
+ qemu_irq_raise(ferr_irq);
}
static void ioportF0_write(void *opaque, uint32_t addr, uint32_t data)
{
- pic_set_irq(13, 0);
+ qemu_irq_lower(ferr_irq);
}
/* TSC handling */
@@ -99,7 +102,7 @@
return intno;
}
-static void pic_irq_request(void *opaque, int level)
+static void pic_irq_request(void *opaque, int irq, int level)
{
CPUState *env = opaque;
if (level)
@@ -401,7 +404,7 @@
static int parallel_irq[MAX_PARALLEL_PORTS] = { 7, 7, 7 };
#ifdef HAS_AUDIO
-static void audio_init (PCIBus *pci_bus)
+static void audio_init (PCIBus *pci_bus, qemu_irq *pic)
{
struct soundhw *c;
int audio_enabled = 0;
@@ -418,7 +421,7 @@
for (c = soundhw; c->name; ++c) {
if (c->enabled) {
if (c->isa) {
- c->init.init_isa (s);
+ c->init.init_isa (s, pic);
}
else {
if (pci_bus) {
@@ -432,13 +435,13 @@
}
#endif
-static void pc_init_ne2k_isa(NICInfo *nd)
+static void pc_init_ne2k_isa(NICInfo *nd, qemu_irq *pic)
{
static int nb_ne2k = 0;
if (nb_ne2k == NE2000_NB_MAX)
return;
- isa_ne2000_init(ne2000_io[nb_ne2k], ne2000_irq[nb_ne2k], nd);
+ isa_ne2000_init(ne2000_io[nb_ne2k], pic[ne2000_irq[nb_ne2k]], nd);
nb_ne2k++;
}
@@ -451,12 +454,15 @@
{
char buf[1024];
int ret, linux_boot, initrd_size, i;
- unsigned long bios_offset, vga_bios_offset, option_rom_offset;
- int bios_size, isa_bios_size;
+ ram_addr_t ram_addr, vga_ram_addr, bios_offset, vga_bios_offset;
+ ram_addr_t initrd_offset;
+ int bios_size, isa_bios_size, vga_bios_size;
PCIBus *pci_bus;
int piix3_devfn = -1;
CPUState *env;
NICInfo *nd;
+ qemu_irq *cpu_irq;
+ qemu_irq *i8259;
linux_boot = (kernel_filename != NULL);
@@ -477,23 +483,24 @@
}
/* allocate RAM */
- cpu_register_physical_memory(0, ram_size, 0);
+ ram_addr = qemu_ram_alloc(ram_size);
+ cpu_register_physical_memory(0, ram_size, ram_addr);
+ /* allocate VGA RAM */
+ vga_ram_addr = qemu_ram_alloc(vga_ram_size);
+
/* BIOS load */
- bios_offset = ram_size + vga_ram_size;
- vga_bios_offset = bios_offset + 256 * 1024;
-
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME);
bios_size = get_image_size(buf);
if (bios_size <= 0 ||
- (bios_size % 65536) != 0 ||
- bios_size > (256 * 1024)) {
+ (bios_size % 65536) != 0) {
goto bios_error;
}
+ bios_offset = qemu_ram_alloc(bios_size);
ret = load_image(buf, phys_ram_base + bios_offset);
if (ret != bios_size) {
bios_error:
- fprintf(stderr, "qemu: could not load PC bios '%s'\n", buf);
+ fprintf(stderr, "qemu: could not load PC BIOS '%s'\n", buf);
exit(1);
}
@@ -503,8 +510,18 @@
} else {
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, VGABIOS_FILENAME);
}
+ vga_bios_size = get_image_size(buf);
+ if (vga_bios_size <= 0 || vga_bios_size > 65536)
+ goto vga_bios_error;
+ vga_bios_offset = qemu_ram_alloc(65536);
+
ret = load_image(buf, phys_ram_base + vga_bios_offset);
-
+ if (ret != vga_bios_size) {
+ vga_bios_error:
+ fprintf(stderr, "qemu: could not load VGA BIOS '%s'\n", buf);
+ exit(1);
+ }
+
/* setup basic memory access */
cpu_register_physical_memory(0xc0000, 0x10000,
vga_bios_offset | IO_MEM_ROM);
@@ -519,20 +536,32 @@
isa_bios_size,
(bios_offset + bios_size - isa_bios_size) | IO_MEM_ROM);
- option_rom_offset = 0;
- for (i = 0; i < nb_option_roms; i++) {
- int offset = bios_offset + bios_size + option_rom_offset;
- int size;
+ {
+ ram_addr_t option_rom_offset;
+ int size, offset;
- size = load_image(option_rom[i], phys_ram_base + offset);
- if ((size + option_rom_offset) > 0x10000) {
- fprintf(stderr, "Too many option ROMS\n");
- exit(1);
- }
- cpu_register_physical_memory(0xd0000 + option_rom_offset,
- size, offset | IO_MEM_ROM);
- option_rom_offset += size + 2047;
- option_rom_offset -= (option_rom_offset % 2048);
+ offset = 0;
+ for (i = 0; i < nb_option_roms; i++) {
+ size = get_image_size(option_rom[i]);
+ if (size < 0) {
+ fprintf(stderr, "Could not load option rom '%s'\n",
+ option_rom[i]);
+ exit(1);
+ }
+ if (size > (0x10000 - offset))
+ goto option_rom_error;
+ option_rom_offset = qemu_ram_alloc(size);
+ ret = load_image(option_rom[i], phys_ram_base + option_rom_offset);
+ if (ret != size) {
+ option_rom_error:
+ fprintf(stderr, "Too many option ROMS\n");
+ exit(1);
+ }
+ size = (size + 4095) & ~4095;
+ cpu_register_physical_memory(0xd0000 + offset,
+ size, option_rom_offset | IO_MEM_ROM);
+ offset += size;
+ }
}
/* map all the bios at the top of memory */
@@ -576,8 +605,28 @@
/* load initrd */
initrd_size = 0;
+ initrd_offset = 0;
if (initrd_filename) {
- initrd_size = load_image(initrd_filename, phys_ram_base + INITRD_LOAD_ADDR);
+ initrd_size = get_image_size (initrd_filename);
+ if (initrd_size > 0) {
+ initrd_offset = (ram_size - initrd_size) & TARGET_PAGE_MASK;
+ /* Leave space for BIOS ACPI tables. */
+ initrd_offset -= ACPI_DATA_SIZE;
+ /* Avoid the last 64k to avoid 2.2.x kernel bugs. */
+ initrd_offset -= 0x10000;
+ if (initrd_offset > MAX_INITRD_LOAD_ADDR)
+ initrd_offset = MAX_INITRD_LOAD_ADDR;
+
+ if (initrd_size > ram_size
+ || initrd_offset < KERNEL_LOAD_ADDR + ret) {
+ fprintf(stderr,
+ "qemu: memory too small for initial ram disk '%s'\n",
+ initrd_filename);
+ exit(1);
+ }
+ initrd_size = load_image(initrd_filename,
+ phys_ram_base + initrd_offset);
+ }
if (initrd_size < 0) {
fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
initrd_filename);
@@ -585,7 +634,7 @@
}
}
if (initrd_size > 0) {
- stl_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x218, INITRD_LOAD_ADDR);
+ stl_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x218, initrd_offset);
stl_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x21c, initrd_size);
}
pstrcpy(phys_ram_base + KERNEL_CMDLINE_ADDR, 4096,
@@ -597,9 +646,13 @@
stw_raw(phys_ram_base + KERNEL_PARAMS_ADDR + 0x210, 0x01);
}
+ cpu_irq = qemu_allocate_irqs(pic_irq_request, first_cpu, 1);
+ i8259 = i8259_init(cpu_irq[0]);
+ ferr_irq = i8259[13];
+
if (pci_enabled) {
- pci_bus = i440fx_init(&i440fx_state);
- piix3_devfn = piix3_init(pci_bus);
+ pci_bus = i440fx_init(&i440fx_state, i8259);
+ piix3_devfn = piix3_init(pci_bus, -1);
} else {
pci_bus = NULL;
}
@@ -612,23 +665,29 @@
if (cirrus_vga_enabled) {
if (pci_enabled) {
pci_cirrus_vga_init(pci_bus,
- ds, phys_ram_base + ram_size, ram_size,
- vga_ram_size);
+ ds, phys_ram_base + vga_ram_addr,
+ vga_ram_addr, vga_ram_size);
} else {
- isa_cirrus_vga_init(ds, phys_ram_base + ram_size, ram_size,
- vga_ram_size);
+ isa_cirrus_vga_init(ds, phys_ram_base + vga_ram_addr,
+ vga_ram_addr, vga_ram_size);
}
+ } else if (vmsvga_enabled) {
+ if (pci_enabled)
+ pci_vmsvga_init(pci_bus, ds, phys_ram_base + ram_size,
+ ram_size, vga_ram_size);
+ else
+ fprintf(stderr, "%s: vmware_vga: no PCI bus\n", __FUNCTION__);
} else {
if (pci_enabled) {
- pci_vga_init(pci_bus, ds, phys_ram_base + ram_size, ram_size,
- vga_ram_size, 0, 0);
+ pci_vga_init(pci_bus, ds, phys_ram_base + vga_ram_addr,
+ vga_ram_addr, vga_ram_size, 0, 0);
} else {
- isa_vga_init(ds, phys_ram_base + ram_size, ram_size,
- vga_ram_size);
+ isa_vga_init(ds, phys_ram_base + vga_ram_addr,
+ vga_ram_addr, vga_ram_size);
}
}
- rtc_state = rtc_init(0x70, 8);
+ rtc_state = rtc_init(0x70, i8259[8]);
register_ioport_read(0x92, 1, 1, ioport92_read, NULL);
register_ioport_write(0x92, 1, 1, ioport92_write, NULL);
@@ -636,8 +695,7 @@
if (pci_enabled) {
ioapic = ioapic_init();
}
- isa_pic = pic_init(pic_irq_request, first_cpu);
- pit = pit_init(0x40, 0);
+ pit = pit_init(0x40, i8259[0]);
pcspk_init(pit);
if (pci_enabled) {
pic_set_alt_irq_func(isa_pic, ioapic_set_irq, ioapic);
@@ -645,14 +703,14 @@
for(i = 0; i < MAX_SERIAL_PORTS; i++) {
if (serial_hds[i]) {
- serial_init(&pic_set_irq_new, isa_pic,
- serial_io[i], serial_irq[i], serial_hds[i]);
+ serial_init(serial_io[i], i8259[serial_irq[i]], serial_hds[i]);
}
}
for(i = 0; i < MAX_PARALLEL_PORTS; i++) {
if (parallel_hds[i]) {
- parallel_init(parallel_io[i], parallel_irq[i], parallel_hds[i]);
+ parallel_init(parallel_io[i], i8259[parallel_irq[i]],
+ parallel_hds[i]);
}
}
@@ -666,11 +724,9 @@
}
}
if (strcmp(nd->model, "ne2k_isa") == 0) {
- pc_init_ne2k_isa(nd);
- } else if (strcmp(nd->model, "usb") == 0) {
- /* ignore */
+ pc_init_ne2k_isa(nd, i8259);
} else if (pci_enabled) {
- pci_nic_init(pci_bus, nd);
+ pci_nic_init(pci_bus, nd, -1);
} else {
fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd->model);
exit(1);
@@ -678,21 +734,21 @@
}
if (pci_enabled) {
- pci_piix3_ide_init(pci_bus, bs_table, piix3_devfn + 1);
+ pci_piix3_ide_init(pci_bus, bs_table, piix3_devfn + 1, i8259);
} else {
for(i = 0; i < 2; i++) {
- isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i],
+ isa_ide_init(ide_iobase[i], ide_iobase2[i], i8259[ide_irq[i]],
bs_table[2 * i], bs_table[2 * i + 1]);
}
}
- kbd_init();
+ i8042_init(i8259[1], i8259[12], 0x60);
DMA_init(0);
#ifdef HAS_AUDIO
- audio_init(pci_enabled ? pci_bus : NULL);
+ audio_init(pci_enabled ? pci_bus : NULL, i8259);
#endif
- floppy_controller = fdctrl_init(6, 2, 0, 0x3f0, fd_table);
+ floppy_controller = fdctrl_init(i8259[6], 2, 0, 0x3f0, fd_table);
cmos_init(ram_size, boot_device, bs_table);
@@ -701,7 +757,13 @@
}
if (pci_enabled && acpi_enabled) {
- piix4_pm_init(pci_bus, piix3_devfn + 3);
+ uint8_t *eeprom_buf = qemu_mallocz(8 * 256); /* XXX: make this persistent */
+ i2c_bus *smbus;
+
+ smbus = piix4_pm_init(pci_bus, piix3_devfn + 3);
+ for (i = 0; i < 8; i++) {
+ smbus_eeprom_device_init(smbus, 0x50 + i, eeprom_buf + (i * 256));
+ }
}
if (i440fx_state) {
@@ -731,7 +793,8 @@
int snapshot,
const char *kernel_filename,
const char *kernel_cmdline,
- const char *initrd_filename)
+ const char *initrd_filename,
+ const char *cpu_model)
{
pc_init1(ram_size, vga_ram_size, boot_device,
ds, fd_filename, snapshot,
@@ -744,7 +807,8 @@
int snapshot,
const char *kernel_filename,
const char *kernel_cmdline,
- const char *initrd_filename)
+ const char *initrd_filename,
+ const char *cpu_model)
{
pc_init1(ram_size, vga_ram_size, boot_device,
ds, fd_filename, snapshot,
Modified: trunk/src/host/qemu-neo1973/hw/pcf5060x.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/pcf5060x.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/pcf5060x.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -12,10 +12,8 @@
#define VERBOSE 1
struct pcf_s {
- int i2c_dir;
- struct i2c_slave_s i2c;
- void *pic;
- int irq;
+ i2c_slave i2c;
+ qemu_irq irq;
int firstbyte;
int charging;
@@ -59,17 +57,14 @@
uint8_t alm_mon;
uint8_t alm_year;
} rtc;
- struct {
- gpio_handler_t fn;
- void *opaque;
- } gpo_handler[6];
+ qemu_irq gpo_handler[6];
uint8_t gpo;
QEMUTimer *onkeylow;
};
-void pcf_reset(struct i2c_slave_s *i2c)
+void pcf_reset(i2c_slave *i2c)
{
- struct pcf_s *s = (struct pcf_s *) i2c->opaque;
+ struct pcf_s *s = (struct pcf_s *) i2c;
time_t ti;
s->charging = 1;
s->reg = 0x00;
@@ -132,7 +127,7 @@
static inline void pcf_update(struct pcf_s *s)
{
- pic_set_irq_new(s->pic, s->irq,
+ qemu_set_irq(s->irq,
(s->intr[0] & ~s->intm[0]) ||
(s->intr[1] & ~s->intm[1]) ||
(s->intr[2] & ~s->intm[2]));
@@ -267,8 +262,8 @@
static void pcf_gpo_set(struct pcf_s *s, int line, int state, int inv)
{
state = (!!state) ^ inv;
- if (s->gpo_handler[line].fn && ((s->gpo & 1) ^ state))
- s->gpo_handler[line].fn(line, state, s->gpo_handler[line].opaque);
+ if (s->gpo_handler[line] && ((s->gpo & 1) ^ state))
+ qemu_set_irq(s->gpo_handler[line], state);
s->gpo &= ~(1 << line);
s->gpo |= state << line;
}
@@ -755,33 +750,33 @@
}
}
-static void pcf_start(void *opaque, int dir)
+static void pcf_event(i2c_slave *i2c, enum i2c_event event)
{
- struct pcf_s *s = (struct pcf_s *) opaque;
- s->i2c_dir = dir;
- s->firstbyte = 1;
+ struct pcf_s *s = (struct pcf_s *) i2c;
+
+ if (event == I2C_START_SEND)
+ s->firstbyte = 1;
}
-static int pcf_tx(void *opaque, uint8_t *data, int len)
+static int pcf_tx(i2c_slave *i2c, uint8_t data)
{
- struct pcf_s *s = (struct pcf_s *) opaque;
+ struct pcf_s *s = (struct pcf_s *) i2c;
/* Interpret register address byte */
- if (s->firstbyte && len && !s->i2c_dir) {
- s->reg = *(data ++);
- len --;
+ if (s->firstbyte) {
+ s->reg = data;
s->firstbyte = 0;
- }
+ } else
+ pcf_write(s, s->reg ++, data);
- while (len --) {
- if (s->i2c_dir)
- *(data ++) = pcf_read(opaque, s->reg ++);
- else
- pcf_write(opaque, s->reg ++, *(data ++));
- }
-
return 0;
}
+static int pcf_rx(i2c_slave *i2c)
+{
+ struct pcf_s *s = (struct pcf_s *) i2c;
+ return pcf_read(s, s->reg ++);
+}
+
static void pcf_onkey1s(void *opaque)
{
struct pcf_s *s = (struct pcf_s *) opaque;
@@ -790,14 +785,14 @@
pcf_update(s);
}
-struct i2c_slave_s *pcf5060x_init(void *pic, int irq, int tsc)
+i2c_slave *pcf5060x_init(i2c_bus *bus, qemu_irq irq, int tsc)
{
- struct pcf_s *s = qemu_mallocz(sizeof(struct pcf_s));
- s->i2c.opaque = s;
- s->i2c.tx = pcf_tx;
- s->i2c.start = pcf_start;
+ struct pcf_s *s = (struct pcf_s *)
+ i2c_slave_init(bus, 0, sizeof(struct pcf_s));
+ s->i2c.event = pcf_event;
+ s->i2c.recv = pcf_rx;
+ s->i2c.send = pcf_tx;
- s->pic = pic;
s->irq = irq;
s->rtc.hz = qemu_new_timer(rt_clock, pcf_rtc_hz, s);
s->onkeylow = qemu_new_timer(vm_clock, pcf_onkey1s, s);
@@ -815,19 +810,17 @@
return &s->i2c;
}
-void pcf_gpo_handler_set(struct i2c_slave_s *i2c, int line,
- gpio_handler_t handler, void *opaque)
+void pcf_gpo_handler_set(i2c_slave *i2c, int line, qemu_irq handler)
{
- struct pcf_s *s = (struct pcf_s *) i2c->opaque;
+ struct pcf_s *s = (struct pcf_s *) i2c;
if (line >= 6 || line < 0)
cpu_abort(cpu_single_env, "%s: No GPO line %i\n", __FUNCTION__, line);
- s->gpo_handler[line].fn = handler;
- s->gpo_handler[line].opaque = opaque;
+ s->gpo_handler[line] = handler;
}
-void pcf_onkey_set(struct i2c_slave_s *i2c, int level)
+void pcf_onkey_set(i2c_slave *i2c, int level)
{
- struct pcf_s *s = (struct pcf_s *) i2c->opaque;
+ struct pcf_s *s = (struct pcf_s *) i2c;
if (level) {
s->oocs |= 1 << 0; /* set ONKEY */
s->intr[0] |= 1 << 0; /* set ONKEYR */
@@ -840,9 +833,9 @@
pcf_update(s);
}
-void pcf_exton_set(struct i2c_slave_s *i2c, int level)
+void pcf_exton_set(i2c_slave *i2c, int level)
{
- struct pcf_s *s = (struct pcf_s *) i2c->opaque;
+ struct pcf_s *s = (struct pcf_s *) i2c;
if (level) {
s->oocs |= 1 << 1; /* set EXTON */
s->intr[0] |= 1 << 3; /* set EXTONR */
Modified: trunk/src/host/qemu-neo1973/hw/pci.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/pci.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/pci.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -33,7 +33,7 @@
uint32_t config_reg; /* XXX: suppress */
/* low level pic */
SetIRQFunc *low_set_irq;
- void *irq_opaque;
+ qemu_irq *irq_opaque;
PCIDevice *devices[256];
PCIDevice *parent_dev;
PCIBus *next;
@@ -43,13 +43,14 @@
};
static void pci_update_mappings(PCIDevice *d);
+static void pci_set_irq(void *opaque, int irq_num, int level);
target_phys_addr_t pci_mem_base;
static int pci_irq_index;
static PCIBus *first_bus;
PCIBus *pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
- void *pic, int devfn_min, int nirq)
+ qemu_irq *pic, int devfn_min, int nirq)
{
PCIBus *bus;
bus = qemu_mallocz(sizeof(PCIBus) + (nirq * sizeof(int)));
@@ -129,6 +130,7 @@
pci_dev->config_write = config_write;
pci_dev->irq_index = pci_irq_index++;
bus->devices[devfn] = pci_dev;
+ pci_dev->irq = qemu_allocate_irqs(pci_set_irq, pci_dev, 4);
return pci_dev;
}
@@ -433,8 +435,9 @@
/* generic PCI irq support */
/* 0 <= irq_num <= 3. level must be 0 or 1 */
-void pci_set_irq(PCIDevice *pci_dev, int irq_num, int level)
+static void pci_set_irq(void *opaque, int irq_num, int level)
{
+ PCIDevice *pci_dev = (PCIDevice *)opaque;
PCIBus *bus;
int change;
@@ -466,11 +469,38 @@
{
{ 0x0100, "SCSI controller"},
{ 0x0101, "IDE controller"},
+ { 0x0102, "Floppy controller"},
+ { 0x0103, "IPI controller"},
+ { 0x0104, "RAID controller"},
+ { 0x0106, "SATA controller"},
+ { 0x0107, "SAS controller"},
+ { 0x0180, "Storage controller"},
{ 0x0200, "Ethernet controller"},
+ { 0x0201, "Token Ring controller"},
+ { 0x0202, "FDDI controller"},
+ { 0x0203, "ATM controller"},
+ { 0x0280, "Network controller"},
{ 0x0300, "VGA controller"},
+ { 0x0301, "XGA controller"},
+ { 0x0302, "3D controller"},
+ { 0x0380, "Display controller"},
+ { 0x0400, "Video controller"},
+ { 0x0401, "Audio controller"},
+ { 0x0402, "Phone"},
+ { 0x0480, "Multimedia controller"},
+ { 0x0500, "RAM controller"},
+ { 0x0501, "Flash controller"},
+ { 0x0580, "Memory controller"},
{ 0x0600, "Host bridge"},
{ 0x0601, "ISA bridge"},
+ { 0x0602, "EISA bridge"},
+ { 0x0603, "MC bridge"},
{ 0x0604, "PCI bridge"},
+ { 0x0605, "PCMCIA bridge"},
+ { 0x0606, "NUBUS bridge"},
+ { 0x0607, "CARDBUS bridge"},
+ { 0x0608, "RACEWAY bridge"},
+ { 0x0680, "Bridge"},
{ 0x0c03, "USB controller"},
{ 0, NULL}
};
@@ -544,14 +574,20 @@
}
/* Initialize a PCI NIC. */
-void pci_nic_init(PCIBus *bus, NICInfo *nd)
+void pci_nic_init(PCIBus *bus, NICInfo *nd, int devfn)
{
if (strcmp(nd->model, "ne2k_pci") == 0) {
- pci_ne2000_init(bus, nd);
+ pci_ne2000_init(bus, nd, devfn);
+ } else if (strcmp(nd->model, "i82551") == 0) {
+ pci_i82551_init(bus, nd, devfn);
+ } else if (strcmp(nd->model, "i82557b") == 0) {
+ pci_i82557b_init(bus, nd, devfn);
+ } else if (strcmp(nd->model, "i82559er") == 0) {
+ pci_i82559er_init(bus, nd, devfn);
} else if (strcmp(nd->model, "rtl8139") == 0) {
- pci_rtl8139_init(bus, nd);
+ pci_rtl8139_init(bus, nd, devfn);
} else if (strcmp(nd->model, "pcnet") == 0) {
- pci_pcnet_init(bus, nd);
+ pci_pcnet_init(bus, nd, devfn);
} else {
fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd->model);
exit (1);
@@ -587,7 +623,7 @@
s = (PCIBridge *)pci_register_device(bus, name, sizeof(PCIBridge),
devfn, NULL, pci_bridge_write_config);
s->dev.config[0x00] = id >> 16;
- s->dev.config[0x01] = id > 24;
+ s->dev.config[0x01] = id >> 24;
s->dev.config[0x02] = id; // device_id
s->dev.config[0x03] = id >> 8;
s->dev.config[0x04] = 0x06; // command = bus master, pci mem
Modified: trunk/src/host/qemu-neo1973/hw/pckbd.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/pckbd.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/pckbd.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -121,6 +121,11 @@
uint8_t pending;
void *kbd;
void *mouse;
+
+ qemu_irq irq_kbd;
+ qemu_irq irq_mouse;
+ target_phys_addr_t base;
+ int it_shift;
} KBDState;
KBDState kbd_state;
@@ -130,26 +135,26 @@
incorrect, but it avoids having to simulate exact delays */
static void kbd_update_irq(KBDState *s)
{
- int irq12_level, irq1_level;
+ int irq_kbd_level, irq_mouse_level;
- irq1_level = 0;
- irq12_level = 0;
+ irq_kbd_level = 0;
+ irq_mouse_level = 0;
s->status &= ~(KBD_STAT_OBF | KBD_STAT_MOUSE_OBF);
if (s->pending) {
s->status |= KBD_STAT_OBF;
- /* kdb data takes priority over aux data. */
+ /* kbd data takes priority over aux data. */
if (s->pending == KBD_PENDING_AUX) {
s->status |= KBD_STAT_MOUSE_OBF;
if (s->mode & KBD_MODE_MOUSE_INT)
- irq12_level = 1;
+ irq_mouse_level = 1;
} else {
if ((s->mode & KBD_MODE_KBD_INT) &&
!(s->mode & KBD_MODE_DISABLE_KBD))
- irq1_level = 1;
+ irq_kbd_level = 1;
}
}
- pic_set_irq(1, irq1_level);
- pic_set_irq(12, irq12_level);
+ qemu_set_irq(s->irq_kbd, irq_kbd_level);
+ qemu_set_irq(s->irq_mouse, irq_mouse_level);
}
static void kbd_update_kbd_irq(void *opaque, int level)
@@ -353,18 +358,89 @@
return 0;
}
-void kbd_init(void)
+void i8042_init(qemu_irq kbd_irq, qemu_irq mouse_irq, uint32_t io_base)
{
KBDState *s = &kbd_state;
-
+
+ s->irq_kbd = kbd_irq;
+ s->irq_mouse = mouse_irq;
+
kbd_reset(s);
register_savevm("pckbd", 0, 3, kbd_save, kbd_load, s);
- register_ioport_read(0x60, 1, 1, kbd_read_data, s);
- register_ioport_write(0x60, 1, 1, kbd_write_data, s);
- register_ioport_read(0x64, 1, 1, kbd_read_status, s);
- register_ioport_write(0x64, 1, 1, kbd_write_command, s);
+ register_ioport_read(io_base, 1, 1, kbd_read_data, s);
+ register_ioport_write(io_base, 1, 1, kbd_write_data, s);
+ register_ioport_read(io_base + 4, 1, 1, kbd_read_status, s);
+ register_ioport_write(io_base + 4, 1, 1, kbd_write_command, s);
s->kbd = ps2_kbd_init(kbd_update_kbd_irq, s);
s->mouse = ps2_mouse_init(kbd_update_aux_irq, s);
+#ifdef TARGET_I386
+ vmmouse_init(s->mouse);
+#endif
qemu_register_reset(kbd_reset, s);
}
+
+/* Memory mapped interface */
+uint32_t kbd_mm_readb (void *opaque, target_phys_addr_t addr)
+{
+ KBDState *s = opaque;
+
+ switch ((addr - s->base) >> s->it_shift) {
+ case 0:
+ return kbd_read_data(s, 0) & 0xff;
+ case 1:
+ return kbd_read_status(s, 0) & 0xff;
+ default:
+ return 0xff;
+ }
+}
+
+void kbd_mm_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+ KBDState *s = opaque;
+
+ switch ((addr - s->base) >> s->it_shift) {
+ case 0:
+ kbd_write_data(s, 0, value & 0xff);
+ break;
+ case 1:
+ kbd_write_command(s, 0, value & 0xff);
+ break;
+ }
+}
+
+static CPUReadMemoryFunc *kbd_mm_read[] = {
+ &kbd_mm_readb,
+ &kbd_mm_readb,
+ &kbd_mm_readb,
+};
+
+static CPUWriteMemoryFunc *kbd_mm_write[] = {
+ &kbd_mm_writeb,
+ &kbd_mm_writeb,
+ &kbd_mm_writeb,
+};
+
+void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq, target_ulong base,
+ int it_shift)
+{
+ KBDState *s = &kbd_state;
+ int s_io_memory;
+
+ s->irq_kbd = kbd_irq;
+ s->irq_mouse = mouse_irq;
+ s->base = base;
+ s->it_shift = it_shift;
+
+ kbd_reset(s);
+ register_savevm("pckbd", 0, 3, kbd_save, kbd_load, s);
+ s_io_memory = cpu_register_io_memory(0, kbd_mm_read, kbd_mm_write, s);
+ cpu_register_physical_memory(base, 8 << it_shift, s_io_memory);
+
+ s->kbd = ps2_kbd_init(kbd_update_kbd_irq, s);
+ s->mouse = ps2_mouse_init(kbd_update_aux_irq, s);
+#ifdef TARGET_I386
+ vmmouse_init(s->mouse);
+#endif
+ qemu_register_reset(kbd_reset, s);
+}
Modified: trunk/src/host/qemu-neo1973/hw/pcnet.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/pcnet.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/pcnet.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -69,7 +69,7 @@
int xmit_pos, recv_pos;
uint8_t buffer[4096];
int tx_busy;
- void (*set_irq_cb)(void *s, int isr);
+ qemu_irq irq;
void (*phys_mem_read)(void *dma_opaque, target_phys_addr_t addr,
uint8_t *buf, int len, int do_bswap);
void (*phys_mem_write)(void *dma_opaque, target_phys_addr_t addr,
@@ -77,14 +77,6 @@
void *dma_opaque;
};
-/* XXX: using bitfields for target memory structures is almost surely
- not portable, so it should be suppressed ASAP */
-#ifdef __GNUC__
-#define PACKED_FIELD(A) A __attribute__ ((packed))
-#else
-#error FixMe
-#endif
-
struct qemu_ether_header {
uint8_t ether_dhost[6];
uint8_t ether_shost[6];
@@ -183,223 +175,291 @@
};
struct pcnet_TMD {
- struct {
- unsigned tbadr:32;
- } tmd0;
- struct {
- unsigned PACKED_FIELD(bcnt:12), PACKED_FIELD(ones:4), PACKED_FIELD(res:7), PACKED_FIELD(bpe:1);
- unsigned PACKED_FIELD(enp:1), PACKED_FIELD(stp:1), PACKED_FIELD(def:1), PACKED_FIELD(one:1);
- unsigned PACKED_FIELD(ltint:1), PACKED_FIELD(nofcs:1), PACKED_FIELD(err:1), PACKED_FIELD(own:1);
- } tmd1;
- struct {
- unsigned PACKED_FIELD(trc:4), PACKED_FIELD(res:12);
- unsigned PACKED_FIELD(tdr:10), PACKED_FIELD(rtry:1), PACKED_FIELD(lcar:1);
- unsigned PACKED_FIELD(lcol:1), PACKED_FIELD(exdef:1), PACKED_FIELD(uflo:1), PACKED_FIELD(buff:1);
- } tmd2;
- struct {
- unsigned res:32;
- } tmd3;
+ uint32_t tbadr;
+ int16_t length;
+ int16_t status;
+ uint32_t misc;
+ uint32_t res;
};
+#define TMDL_BCNT_MASK 0x0fff
+#define TMDL_BCNT_SH 0
+#define TMDL_ONES_MASK 0xf000
+#define TMDL_ONES_SH 12
+
+#define TMDS_BPE_MASK 0x0080
+#define TMDS_BPE_SH 7
+#define TMDS_ENP_MASK 0x0100
+#define TMDS_ENP_SH 8
+#define TMDS_STP_MASK 0x0200
+#define TMDS_STP_SH 9
+#define TMDS_DEF_MASK 0x0400
+#define TMDS_DEF_SH 10
+#define TMDS_ONE_MASK 0x0800
+#define TMDS_ONE_SH 11
+#define TMDS_LTINT_MASK 0x1000
+#define TMDS_LTINT_SH 12
+#define TMDS_NOFCS_MASK 0x2000
+#define TMDS_NOFCS_SH 13
+#define TMDS_ERR_MASK 0x4000
+#define TMDS_ERR_SH 14
+#define TMDS_OWN_MASK 0x8000
+#define TMDS_OWN_SH 15
+
+#define TMDM_TRC_MASK 0x0000000f
+#define TMDM_TRC_SH 0
+#define TMDM_TDR_MASK 0x03ff0000
+#define TMDM_TDR_SH 16
+#define TMDM_RTRY_MASK 0x04000000
+#define TMDM_RTRY_SH 26
+#define TMDM_LCAR_MASK 0x08000000
+#define TMDM_LCAR_SH 27
+#define TMDM_LCOL_MASK 0x10000000
+#define TMDM_LCOL_SH 28
+#define TMDM_EXDEF_MASK 0x20000000
+#define TMDM_EXDEF_SH 29
+#define TMDM_UFLO_MASK 0x40000000
+#define TMDM_UFLO_SH 30
+#define TMDM_BUFF_MASK 0x80000000
+#define TMDM_BUFF_SH 31
+
struct pcnet_RMD {
- struct {
- unsigned rbadr:32;
- } rmd0;
- struct {
- unsigned PACKED_FIELD(bcnt:12), PACKED_FIELD(ones:4), PACKED_FIELD(res:4);
- unsigned PACKED_FIELD(bam:1), PACKED_FIELD(lafm:1), PACKED_FIELD(pam:1), PACKED_FIELD(bpe:1);
- unsigned PACKED_FIELD(enp:1), PACKED_FIELD(stp:1), PACKED_FIELD(buff:1), PACKED_FIELD(crc:1);
- unsigned PACKED_FIELD(oflo:1), PACKED_FIELD(fram:1), PACKED_FIELD(err:1), PACKED_FIELD(own:1);
- } rmd1;
- struct {
- unsigned PACKED_FIELD(mcnt:12), PACKED_FIELD(zeros:4);
- unsigned PACKED_FIELD(rpc:8), PACKED_FIELD(rcc:8);
- } rmd2;
- struct {
- unsigned res:32;
- } rmd3;
+ uint32_t rbadr;
+ int16_t buf_length;
+ int16_t status;
+ uint32_t msg_length;
+ uint32_t res;
};
+#define RMDL_BCNT_MASK 0x0fff
+#define RMDL_BCNT_SH 0
+#define RMDL_ONES_MASK 0xf000
+#define RMDL_ONES_SH 12
-#define PRINT_TMD(T) printf( \
- "TMD0 : TBADR=0x%08x\n" \
+#define RMDS_BAM_MASK 0x0010
+#define RMDS_BAM_SH 4
+#define RMDS_LFAM_MASK 0x0020
+#define RMDS_LFAM_SH 5
+#define RMDS_PAM_MASK 0x0040
+#define RMDS_PAM_SH 6
+#define RMDS_BPE_MASK 0x0080
+#define RMDS_BPE_SH 7
+#define RMDS_ENP_MASK 0x0100
+#define RMDS_ENP_SH 8
+#define RMDS_STP_MASK 0x0200
+#define RMDS_STP_SH 9
+#define RMDS_BUFF_MASK 0x0400
+#define RMDS_BUFF_SH 10
+#define RMDS_CRC_MASK 0x0800
+#define RMDS_CRC_SH 11
+#define RMDS_OFLO_MASK 0x1000
+#define RMDS_OFLO_SH 12
+#define RMDS_FRAM_MASK 0x2000
+#define RMDS_FRAM_SH 13
+#define RMDS_ERR_MASK 0x4000
+#define RMDS_ERR_SH 14
+#define RMDS_OWN_MASK 0x8000
+#define RMDS_OWN_SH 15
+
+#define RMDM_MCNT_MASK 0x00000fff
+#define RMDM_MCNT_SH 0
+#define RMDM_ZEROS_MASK 0x0000f000
+#define RMDM_ZEROS_SH 12
+#define RMDM_RPC_MASK 0x00ff0000
+#define RMDM_RPC_SH 16
+#define RMDM_RCC_MASK 0xff000000
+#define RMDM_RCC_SH 24
+
+#define SET_FIELD(regp, name, field, value) \
+ (*(regp) = (*(regp) & ~(name ## _ ## field ## _MASK)) \
+ | ((value) << name ## _ ## field ## _SH))
+
+#define GET_FIELD(reg, name, field) \
+ (((reg) & name ## _ ## field ## _MASK) >> name ## _ ## field ## _SH)
+
+#define PRINT_TMD(T) printf( \
+ "TMD0 : TBADR=0x%08x\n" \
"TMD1 : OWN=%d, ERR=%d, FCS=%d, LTI=%d, " \
"ONE=%d, DEF=%d, STP=%d, ENP=%d,\n" \
" BPE=%d, BCNT=%d\n" \
"TMD2 : BUF=%d, UFL=%d, EXD=%d, LCO=%d, " \
"LCA=%d, RTR=%d,\n" \
" TDR=%d, TRC=%d\n", \
- (T)->tmd0.tbadr, \
- (T)->tmd1.own, (T)->tmd1.err, (T)->tmd1.nofcs, \
- (T)->tmd1.ltint, (T)->tmd1.one, (T)->tmd1.def, \
- (T)->tmd1.stp, (T)->tmd1.enp, (T)->tmd1.bpe, \
- 4096-(T)->tmd1.bcnt, \
- (T)->tmd2.buff, (T)->tmd2.uflo, (T)->tmd2.exdef,\
- (T)->tmd2.lcol, (T)->tmd2.lcar, (T)->tmd2.rtry, \
- (T)->tmd2.tdr, (T)->tmd2.trc)
+ (T)->tbadr, \
+ GET_FIELD((T)->status, TMDS, OWN), \
+ GET_FIELD((T)->status, TMDS, ERR), \
+ GET_FIELD((T)->status, TMDS, NOFCS), \
+ GET_FIELD((T)->status, TMDS, LTINT), \
+ GET_FIELD((T)->status, TMDS, ONE), \
+ GET_FIELD((T)->status, TMDS, DEF), \
+ GET_FIELD((T)->status, TMDS, STP), \
+ GET_FIELD((T)->status, TMDS, ENP), \
+ GET_FIELD((T)->status, TMDS, BPE), \
+ 4096-GET_FIELD((T)->length, TMDL, BCNT), \
+ GET_FIELD((T)->misc, TMDM, BUFF), \
+ GET_FIELD((T)->misc, TMDM, UFLO), \
+ GET_FIELD((T)->misc, TMDM, EXDEF), \
+ GET_FIELD((T)->misc, TMDM, LCOL), \
+ GET_FIELD((T)->misc, TMDM, LCAR), \
+ GET_FIELD((T)->misc, TMDM, RTRY), \
+ GET_FIELD((T)->misc, TMDM, TDR), \
+ GET_FIELD((T)->misc, TMDM, TRC))
-#define PRINT_RMD(R) printf( \
- "RMD0 : RBADR=0x%08x\n" \
+#define PRINT_RMD(R) printf( \
+ "RMD0 : RBADR=0x%08x\n" \
"RMD1 : OWN=%d, ERR=%d, FRAM=%d, OFLO=%d, " \
"CRC=%d, BUFF=%d, STP=%d, ENP=%d,\n " \
- "BPE=%d, PAM=%d, LAFM=%d, BAM=%d, ONES=%d, BCNT=%d\n" \
+ "BPE=%d, PAM=%d, LAFM=%d, BAM=%d, ONES=%d, BCNT=%d\n" \
"RMD2 : RCC=%d, RPC=%d, MCNT=%d, ZEROS=%d\n", \
- (R)->rmd0.rbadr, \
- (R)->rmd1.own, (R)->rmd1.err, (R)->rmd1.fram, \
- (R)->rmd1.oflo, (R)->rmd1.crc, (R)->rmd1.buff, \
- (R)->rmd1.stp, (R)->rmd1.enp, (R)->rmd1.bpe, \
- (R)->rmd1.pam, (R)->rmd1.lafm, (R)->rmd1.bam, \
- (R)->rmd1.ones, 4096-(R)->rmd1.bcnt, \
- (R)->rmd2.rcc, (R)->rmd2.rpc, (R)->rmd2.mcnt, \
- (R)->rmd2.zeros)
+ (R)->rbadr, \
+ GET_FIELD((R)->status, RMDS, OWN), \
+ GET_FIELD((R)->status, RMDS, ERR), \
+ GET_FIELD((R)->status, RMDS, FRAM), \
+ GET_FIELD((R)->status, RMDS, OFLO), \
+ GET_FIELD((R)->status, RMDS, CRC), \
+ GET_FIELD((R)->status, RMDS, BUFF), \
+ GET_FIELD((R)->status, RMDS, STP), \
+ GET_FIELD((R)->status, RMDS, ENP), \
+ GET_FIELD((R)->status, RMDS, BPE), \
+ GET_FIELD((R)->status, RMDS, PAM), \
+ GET_FIELD((R)->status, RMDS, LFAM), \
+ GET_FIELD((R)->status, RMDS, BAM), \
+ GET_FIELD((R)->buf_length, RMDL, ONES), \
+ 4096-GET_FIELD((R)->buf_length, RMDL, BCNT), \
+ GET_FIELD((R)->msg_length, RMDM, RCC), \
+ GET_FIELD((R)->msg_length, RMDM, RPC), \
+ GET_FIELD((R)->msg_length, RMDM, MCNT), \
+ GET_FIELD((R)->msg_length, RMDM, ZEROS))
-static inline void pcnet_tmd_load(PCNetState *s, struct pcnet_TMD *tmd1,
+static inline void pcnet_tmd_load(PCNetState *s, struct pcnet_TMD *tmd,
target_phys_addr_t addr)
{
- uint32_t *tmd = (uint32_t *)tmd1;
-
- if (!BCR_SWSTYLE(s)) {
- uint16_t xda[4];
- s->phys_mem_read(s->dma_opaque, addr,
- (void *)&xda[0], sizeof(xda), 0);
- le16_to_cpus(&xda[0]);
- le16_to_cpus(&xda[1]);
- le16_to_cpus(&xda[2]);
- le16_to_cpus(&xda[3]);
- tmd[0] = (xda[0]&0xffff) |
- ((xda[1]&0x00ff) << 16);
- tmd[1] = (xda[2]&0xffff)|
- ((xda[1] & 0xff00) << 16);
- tmd[2] =
- (xda[3] & 0xffff) << 16;
- tmd[3] = 0;
+ if (!BCR_SSIZE32(s)) {
+ struct {
+ uint32_t tbadr;
+ int16_t length;
+ int16_t status;
+ } xda;
+ s->phys_mem_read(s->dma_opaque, addr, (void *)&xda, sizeof(xda), 0);
+ tmd->tbadr = le32_to_cpu(xda.tbadr) & 0xffffff;
+ tmd->length = le16_to_cpu(xda.length);
+ tmd->status = (le32_to_cpu(xda.tbadr) >> 16) & 0xff00;
+ tmd->misc = le16_to_cpu(xda.status) << 16;
+ tmd->res = 0;
} else {
- uint32_t xda[4];
- s->phys_mem_read(s->dma_opaque, addr,
- (void *)&xda[0], sizeof(xda), 0);
- le32_to_cpus(&xda[0]);
- le32_to_cpus(&xda[1]);
- le32_to_cpus(&xda[2]);
- le32_to_cpus(&xda[3]);
- if (BCR_SWSTYLE(s) != 3) {
- memcpy(tmd, xda, sizeof(xda));
- } else {
- tmd[0] = xda[2];
- tmd[1] = xda[1];
- tmd[2] = xda[0];
- tmd[3] = xda[3];
+ s->phys_mem_read(s->dma_opaque, addr, (void *)tmd, sizeof(*tmd), 0);
+ le32_to_cpus(&tmd->tbadr);
+ le16_to_cpus(&tmd->length);
+ le16_to_cpus(&tmd->status);
+ le32_to_cpus(&tmd->misc);
+ le32_to_cpus(&tmd->res);
+ if (BCR_SWSTYLE(s) == 3) {
+ uint32_t tmp = tmd->tbadr;
+ tmd->tbadr = tmd->misc;
+ tmd->misc = tmp;
}
}
}
-static inline void pcnet_tmd_store(PCNetState *s, const struct pcnet_TMD *tmd1,
+static inline void pcnet_tmd_store(PCNetState *s, const struct pcnet_TMD *tmd,
target_phys_addr_t addr)
{
- const uint32_t *tmd = (const uint32_t *)tmd1;
- if (!BCR_SWSTYLE(s)) {
- uint16_t xda[4];
- xda[0] = tmd[0] & 0xffff;
- xda[1] = ((tmd[0]>>16)&0x00ff) |
- ((tmd[1]>>16)&0xff00);
- xda[2] = tmd[1] & 0xffff;
- xda[3] = tmd[2] >> 16;
- cpu_to_le16s(&xda[0]);
- cpu_to_le16s(&xda[1]);
- cpu_to_le16s(&xda[2]);
- cpu_to_le16s(&xda[3]);
- s->phys_mem_write(s->dma_opaque, addr,
- (void *)&xda[0], sizeof(xda), 0);
+ if (!BCR_SSIZE32(s)) {
+ struct {
+ uint32_t tbadr;
+ int16_t length;
+ int16_t status;
+ } xda;
+ xda.tbadr = cpu_to_le32((tmd->tbadr & 0xffffff) |
+ ((tmd->status & 0xff00) << 16));
+ xda.length = cpu_to_le16(tmd->length);
+ xda.status = cpu_to_le16(tmd->misc >> 16);
+ s->phys_mem_write(s->dma_opaque, addr, (void *)&xda, sizeof(xda), 0);
} else {
- uint32_t xda[4];
- if (BCR_SWSTYLE(s) != 3) {
- memcpy(xda, tmd, sizeof(xda));
- } else {
- xda[0] = tmd[2];
- xda[1] = tmd[1];
- xda[2] = tmd[0];
- xda[3] = tmd[3];
+ struct {
+ uint32_t tbadr;
+ int16_t length;
+ int16_t status;
+ uint32_t misc;
+ uint32_t res;
+ } xda;
+ xda.tbadr = cpu_to_le32(tmd->tbadr);
+ xda.length = cpu_to_le16(tmd->length);
+ xda.status = cpu_to_le16(tmd->status);
+ xda.misc = cpu_to_le32(tmd->misc);
+ xda.res = cpu_to_le32(tmd->res);
+ if (BCR_SWSTYLE(s) == 3) {
+ uint32_t tmp = xda.tbadr;
+ xda.tbadr = xda.misc;
+ xda.misc = tmp;
}
- cpu_to_le32s(&xda[0]);
- cpu_to_le32s(&xda[1]);
- cpu_to_le32s(&xda[2]);
- cpu_to_le32s(&xda[3]);
- s->phys_mem_write(s->dma_opaque, addr,
- (void *)&xda[0], sizeof(xda), 0);
+ s->phys_mem_write(s->dma_opaque, addr, (void *)&xda, sizeof(xda), 0);
}
}
-static inline void pcnet_rmd_load(PCNetState *s, struct pcnet_RMD *rmd1,
+static inline void pcnet_rmd_load(PCNetState *s, struct pcnet_RMD *rmd,
target_phys_addr_t addr)
{
- uint32_t *rmd = (uint32_t *)rmd1;
-
- if (!BCR_SWSTYLE(s)) {
- uint16_t rda[4];
- s->phys_mem_read(s->dma_opaque, addr,
- (void *)&rda[0], sizeof(rda), 0);
- le16_to_cpus(&rda[0]);
- le16_to_cpus(&rda[1]);
- le16_to_cpus(&rda[2]);
- le16_to_cpus(&rda[3]);
- rmd[0] = (rda[0]&0xffff)|
- ((rda[1] & 0x00ff) << 16);
- rmd[1] = (rda[2]&0xffff)|
- ((rda[1] & 0xff00) << 16);
- rmd[2] = rda[3] & 0xffff;
- rmd[3] = 0;
+ if (!BCR_SSIZE32(s)) {
+ struct {
+ uint32_t rbadr;
+ int16_t buf_length;
+ int16_t msg_length;
+ } rda;
+ s->phys_mem_read(s->dma_opaque, addr, (void *)&rda, sizeof(rda), 0);
+ rmd->rbadr = le32_to_cpu(rda.rbadr) & 0xffffff;
+ rmd->buf_length = le16_to_cpu(rda.buf_length);
+ rmd->status = (le32_to_cpu(rda.rbadr) >> 16) & 0xff00;
+ rmd->msg_length = le16_to_cpu(rda.msg_length);
+ rmd->res = 0;
} else {
- uint32_t rda[4];
- s->phys_mem_read(s->dma_opaque, addr,
- (void *)&rda[0], sizeof(rda), 0);
- le32_to_cpus(&rda[0]);
- le32_to_cpus(&rda[1]);
- le32_to_cpus(&rda[2]);
- le32_to_cpus(&rda[3]);
- if (BCR_SWSTYLE(s) != 3) {
- memcpy(rmd, rda, sizeof(rda));
- } else {
- rmd[0] = rda[2];
- rmd[1] = rda[1];
- rmd[2] = rda[0];
- rmd[3] = rda[3];
+ s->phys_mem_read(s->dma_opaque, addr, (void *)rmd, sizeof(*rmd), 0);
+ le32_to_cpus(&rmd->rbadr);
+ le16_to_cpus(&rmd->buf_length);
+ le16_to_cpus(&rmd->status);
+ le32_to_cpus(&rmd->msg_length);
+ le32_to_cpus(&rmd->res);
+ if (BCR_SWSTYLE(s) == 3) {
+ uint32_t tmp = rmd->rbadr;
+ rmd->rbadr = rmd->msg_length;
+ rmd->msg_length = tmp;
}
}
}
-static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd1,
+static inline void pcnet_rmd_store(PCNetState *s, struct pcnet_RMD *rmd,
target_phys_addr_t addr)
{
- const uint32_t *rmd = (const uint32_t *)rmd1;
-
- if (!BCR_SWSTYLE(s)) {
- uint16_t rda[4];
- rda[0] = rmd[0] & 0xffff;
- rda[1] = ((rmd[0]>>16)&0xff)|
- ((rmd[1]>>16)&0xff00);
- rda[2] = rmd[1] & 0xffff;
- rda[3] = rmd[2] & 0xffff;
- cpu_to_le16s(&rda[0]);
- cpu_to_le16s(&rda[1]);
- cpu_to_le16s(&rda[2]);
- cpu_to_le16s(&rda[3]);
- s->phys_mem_write(s->dma_opaque, addr,
- (void *)&rda[0], sizeof(rda), 0);
+ if (!BCR_SSIZE32(s)) {
+ struct {
+ uint32_t rbadr;
+ int16_t buf_length;
+ int16_t msg_length;
+ } rda;
+ rda.rbadr = cpu_to_le32((rmd->rbadr & 0xffffff) |
+ ((rmd->status & 0xff00) << 16));
+ rda.buf_length = cpu_to_le16(rmd->buf_length);
+ rda.msg_length = cpu_to_le16(rmd->msg_length);
+ s->phys_mem_write(s->dma_opaque, addr, (void *)&rda, sizeof(rda), 0);
} else {
- uint32_t rda[4];
- if (BCR_SWSTYLE(s) != 3) {
- memcpy(rda, rmd, sizeof(rda));
- } else {
- rda[0] = rmd[2];
- rda[1] = rmd[1];
- rda[2] = rmd[0];
- rda[3] = rmd[3];
+ struct {
+ uint32_t rbadr;
+ int16_t buf_length;
+ int16_t status;
+ uint32_t msg_length;
+ uint32_t res;
+ } rda;
+ rda.rbadr = cpu_to_le32(rmd->rbadr);
+ rda.buf_length = cpu_to_le16(rmd->buf_length);
+ rda.status = cpu_to_le16(rmd->status);
+ rda.msg_length = cpu_to_le32(rmd->msg_length);
+ rda.res = cpu_to_le32(rmd->res);
+ if (BCR_SWSTYLE(s) == 3) {
+ uint32_t tmp = rda.rbadr;
+ rda.rbadr = rda.msg_length;
+ rda.msg_length = tmp;
}
- cpu_to_le32s(&rda[0]);
- cpu_to_le32s(&rda[1]);
- cpu_to_le32s(&rda[2]);
- cpu_to_le32s(&rda[3]);
- s->phys_mem_write(s->dma_opaque, addr,
- (void *)&rda[0], sizeof(rda), 0);
+ s->phys_mem_write(s->dma_opaque, addr, (void *)&rda, sizeof(rda), 0);
}
}
@@ -417,14 +477,14 @@
#define CHECK_RMD(ADDR,RES) do { \
struct pcnet_RMD rmd; \
RMDLOAD(&rmd,(ADDR)); \
- (RES) |= (rmd.rmd1.ones != 15) \
- || (rmd.rmd2.zeros != 0); \
+ (RES) |= (GET_FIELD(rmd.buf_length, RMDL, ONES) != 15) \
+ || (GET_FIELD(rmd.msg_length, RMDM, ZEROS) != 0); \
} while (0)
#define CHECK_TMD(ADDR,RES) do { \
struct pcnet_TMD tmd; \
TMDLOAD(&tmd,(ADDR)); \
- (RES) |= (tmd.tmd1.ones != 15); \
+ (RES) |= (GET_FIELD(tmd.length, TMDL, ONES) != 15); \
} while (0)
#else
@@ -434,8 +494,8 @@
case 0x00: \
do { \
uint16_t rda[4]; \
- s->phys_mem_read(s->dma_opaque, (ADDR), \
- (void *)&rda[0], sizeof(rda), 0); \
+ s->phys_mem_read(s->dma_opaque, (ADDR), \
+ (void *)&rda[0], sizeof(rda), 0); \
(RES) |= (rda[2] & 0xf000)!=0xf000; \
(RES) |= (rda[3] & 0xf000)!=0x0000; \
} while (0); \
@@ -444,7 +504,7 @@
case 0x02: \
do { \
uint32_t rda[4]; \
- s->phys_mem_read(s->dma_opaque, (ADDR), \
+ s->phys_mem_read(s->dma_opaque, (ADDR), \
(void *)&rda[0], sizeof(rda), 0); \
(RES) |= (rda[1] & 0x0000f000L)!=0x0000f000L; \
(RES) |= (rda[2] & 0x0000f000L)!=0x00000000L; \
@@ -453,7 +513,7 @@
case 0x03: \
do { \
uint32_t rda[4]; \
- s->phys_mem_read(s->dma_opaque, (ADDR), \
+ s->phys_mem_read(s->dma_opaque, (ADDR), \
(void *)&rda[0], sizeof(rda), 0); \
(RES) |= (rda[0] & 0x0000f000L)!=0x00000000L; \
(RES) |= (rda[1] & 0x0000f000L)!=0x0000f000L; \
@@ -467,9 +527,9 @@
case 0x00: \
do { \
uint16_t xda[4]; \
- s->phys_mem_read(s->dma_opaque, (ADDR), \
- (void *)&xda[0], sizeof(xda), 0); \
- (RES) |= (xda[2] & 0xf000)!=0xf000;\
+ s->phys_mem_read(s->dma_opaque, (ADDR), \
+ (void *)&xda[0], sizeof(xda), 0); \
+ (RES) |= (xda[2] & 0xf000)!=0xf000; \
} while (0); \
break; \
case 0x01: \
@@ -477,8 +537,8 @@
case 0x03: \
do { \
uint32_t xda[4]; \
- s->phys_mem_read(s->dma_opaque, (ADDR), \
- (void *)&xda[0], sizeof(xda), 0); \
+ s->phys_mem_read(s->dma_opaque, (ADDR), \
+ (void *)&xda[0], sizeof(xda), 0); \
(RES) |= (xda[1] & 0x0000f000L)!=0x0000f000L; \
} while (0); \
break; \
@@ -488,15 +548,15 @@
#endif
#define PRINT_PKTHDR(BUF) do { \
- struct qemu_ether_header *hdr = (void *)(BUF); \
- printf("packet dhost=%02x:%02x:%02x:%02x:%02x:%02x, " \
- "shost=%02x:%02x:%02x:%02x:%02x:%02x, " \
- "type=0x%04x\n", \
+ struct qemu_ether_header *hdr = (void *)(BUF); \
+ printf("packet dhost=%02x:%02x:%02x:%02x:%02x:%02x, " \
+ "shost=%02x:%02x:%02x:%02x:%02x:%02x, " \
+ "type=0x%04x\n", \
hdr->ether_dhost[0],hdr->ether_dhost[1],hdr->ether_dhost[2], \
hdr->ether_dhost[3],hdr->ether_dhost[4],hdr->ether_dhost[5], \
hdr->ether_shost[0],hdr->ether_shost[1],hdr->ether_shost[2], \
hdr->ether_shost[3],hdr->ether_shost[4],hdr->ether_shost[5], \
- be16_to_cpu(hdr->ether_type)); \
+ be16_to_cpu(hdr->ether_type)); \
} while (0)
#define MULTICAST_FILTER_LEN 8
@@ -763,14 +823,14 @@
printf("pcnet: INTA=%d\n", isr);
#endif
}
- s->set_irq_cb(s, isr);
+ qemu_set_irq(s->irq, isr);
s->isr = isr;
}
static void pcnet_init(PCNetState *s)
{
int rlen, tlen;
- uint16_t *padr, *ladrf, mode;
+ uint16_t padr[3], ladrf[4], mode;
uint32_t rdra, tdra;
#ifdef PCNET_DEBUG
@@ -781,22 +841,30 @@
struct pcnet_initblk32 initblk;
s->phys_mem_read(s->dma_opaque, PHYSADDR(s,CSR_IADR(s)),
(uint8_t *)&initblk, sizeof(initblk), 0);
- mode = initblk.mode;
+ mode = le16_to_cpu(initblk.mode);
rlen = initblk.rlen >> 4;
tlen = initblk.tlen >> 4;
- ladrf = initblk.ladrf;
- padr = initblk.padr;
+ ladrf[0] = le16_to_cpu(initblk.ladrf[0]);
+ ladrf[1] = le16_to_cpu(initblk.ladrf[1]);
+ ladrf[2] = le16_to_cpu(initblk.ladrf[2]);
+ ladrf[3] = le16_to_cpu(initblk.ladrf[3]);
+ padr[0] = le16_to_cpu(initblk.padr[0]);
+ padr[1] = le16_to_cpu(initblk.padr[1]);
+ padr[2] = le16_to_cpu(initblk.padr[2]);
rdra = le32_to_cpu(initblk.rdra);
tdra = le32_to_cpu(initblk.tdra);
- s->rdra = PHYSADDR(s,initblk.rdra);
- s->tdra = PHYSADDR(s,initblk.tdra);
} else {
struct pcnet_initblk16 initblk;
s->phys_mem_read(s->dma_opaque, PHYSADDR(s,CSR_IADR(s)),
(uint8_t *)&initblk, sizeof(initblk), 0);
- mode = initblk.mode;
- ladrf = initblk.ladrf;
- padr = initblk.padr;
+ mode = le16_to_cpu(initblk.mode);
+ ladrf[0] = le16_to_cpu(initblk.ladrf[0]);
+ ladrf[1] = le16_to_cpu(initblk.ladrf[1]);
+ ladrf[2] = le16_to_cpu(initblk.ladrf[2]);
+ ladrf[3] = le16_to_cpu(initblk.ladrf[3]);
+ padr[0] = le16_to_cpu(initblk.padr[0]);
+ padr[1] = le16_to_cpu(initblk.padr[1]);
+ padr[2] = le16_to_cpu(initblk.padr[2]);
rdra = le32_to_cpu(initblk.rdra);
tdra = le32_to_cpu(initblk.tdra);
rlen = rdra >> 29;
@@ -804,22 +872,22 @@
rdra &= 0x00ffffff;
tdra &= 0x00ffffff;
}
-
+
#if defined(PCNET_DEBUG)
- printf("rlen=%d tlen=%d\n",
- rlen, tlen);
+ printf("rlen=%d tlen=%d\n", rlen, tlen);
#endif
+
CSR_RCVRL(s) = (rlen < 9) ? (1 << rlen) : 512;
CSR_XMTRL(s) = (tlen < 9) ? (1 << tlen) : 512;
s->csr[ 6] = (tlen << 12) | (rlen << 8);
- s->csr[15] = le16_to_cpu(mode);
- s->csr[ 8] = le16_to_cpu(ladrf[0]);
- s->csr[ 9] = le16_to_cpu(ladrf[1]);
- s->csr[10] = le16_to_cpu(ladrf[2]);
- s->csr[11] = le16_to_cpu(ladrf[3]);
- s->csr[12] = le16_to_cpu(padr[0]);
- s->csr[13] = le16_to_cpu(padr[1]);
- s->csr[14] = le16_to_cpu(padr[2]);
+ s->csr[15] = mode;
+ s->csr[ 8] = ladrf[0];
+ s->csr[ 9] = ladrf[1];
+ s->csr[10] = ladrf[2];
+ s->csr[11] = ladrf[3];
+ s->csr[12] = padr[0];
+ s->csr[13] = padr[1];
+ s->csr[14] = padr[2];
s->rdra = PHYSADDR(s, rdra);
s->tdra = PHYSADDR(s, tdra);
@@ -914,12 +982,12 @@
if (CSR_CRDA(s)) {
struct pcnet_RMD rmd;
RMDLOAD(&rmd, PHYSADDR(s,CSR_CRDA(s)));
- CSR_CRBC(s) = rmd.rmd1.bcnt;
- CSR_CRST(s) = ((uint32_t *)&rmd)[1] >> 16;
+ CSR_CRBC(s) = GET_FIELD(rmd.buf_length, RMDL, BCNT);
+ CSR_CRST(s) = rmd.status;
#ifdef PCNET_DEBUG_RMD_X
- printf("CRDA=0x%08x CRST=0x%04x RCVRC=%d RMD1=0x%08x RMD2=0x%08x\n",
+ printf("CRDA=0x%08x CRST=0x%04x RCVRC=%d RMDL=0x%04x RMDS=0x%04x RMDM=0x%08x\n",
PHYSADDR(s,CSR_CRDA(s)), CSR_CRST(s), CSR_RCVRC(s),
- ((uint32_t *)&rmd)[1], ((uint32_t *)&rmd)[2]);
+ rmd.buf_length, rmd.status, rmd.msg_length);
PRINT_RMD(&rmd);
#endif
} else {
@@ -929,8 +997,8 @@
if (CSR_NRDA(s)) {
struct pcnet_RMD rmd;
RMDLOAD(&rmd, PHYSADDR(s,CSR_NRDA(s)));
- CSR_NRBC(s) = rmd.rmd1.bcnt;
- CSR_NRST(s) = ((uint32_t *)&rmd)[1] >> 16;
+ CSR_NRBC(s) = GET_FIELD(rmd.buf_length, RMDL, BCNT);
+ CSR_NRST(s) = rmd.status;
} else {
CSR_NRBC(s) = CSR_NRST(s) = 0;
}
@@ -943,7 +1011,7 @@
if (s->tdra) {
target_phys_addr_t cxda = s->tdra +
(CSR_XMTRL(s) - CSR_XMTRC(s)) *
- (BCR_SWSTYLE(s) ? 16 : 8 );
+ (BCR_SWSTYLE(s) ? 16 : 8);
int bad = 0;
CHECK_TMD(PHYSADDR(s, cxda),bad);
if (!bad) {
@@ -955,8 +1023,7 @@
}
s->csr[34] = cxda & 0xffff;
s->csr[35] = cxda >> 16;
-#ifdef PCNET_DEBUG
- } else {
+#ifdef PCNET_DEBUG_X
printf("pcnet: BAD TMD XDA=0x%08x\n", PHYSADDR(s,cxda));
#endif
}
@@ -967,8 +1034,8 @@
TMDLOAD(&tmd, PHYSADDR(s,CSR_CXDA(s)));
- CSR_CXBC(s) = tmd.tmd1.bcnt;
- CSR_CXST(s) = ((uint32_t *)&tmd)[1] >> 16;
+ CSR_CXBC(s) = GET_FIELD(tmd.length, TMDL, BCNT);
+ CSR_CXST(s) = tmd.status;
} else {
CSR_CXBC(s) = CSR_CXST(s) = 0;
}
@@ -1029,7 +1096,7 @@
(CSR_RCVRL(s) - rcvrc) *
(BCR_SWSTYLE(s) ? 16 : 8 );
RMDLOAD(&rmd, PHYSADDR(s,nrda));
- if (rmd.rmd1.own) {
+ if (GET_FIELD(rmd.status, RMDS, OWN)) {
#ifdef PCNET_DEBUG_RMD
printf("pcnet - scan buffer: RCVRC=%d PREV_RCVRC=%d\n",
rcvrc, CSR_RCVRC(s));
@@ -1086,14 +1153,15 @@
RMDLOAD(&rmd, PHYSADDR(s,crda));
/*if (!CSR_LAPPEN(s))*/
- rmd.rmd1.stp = 1;
+ SET_FIELD(&rmd.status, RMDS, STP, 1);
#define PCNET_RECV_STORE() do { \
- int count = MIN(4096 - rmd.rmd1.bcnt,size); \
- target_phys_addr_t rbadr = PHYSADDR(s, rmd.rmd0.rbadr); \
- s->phys_mem_write(s->dma_opaque, rbadr, src, count, CSR_BSWP(s)); \
+ int count = MIN(4096 - GET_FIELD(rmd.buf_length, RMDL, BCNT),size); \
+ target_phys_addr_t rbadr = PHYSADDR(s, rmd.rbadr); \
+ s->phys_mem_write(s->dma_opaque, rbadr, src, count, CSR_BSWP(s)); \
src += count; size -= count; \
- rmd.rmd2.mcnt = count; rmd.rmd1.own = 0; \
+ SET_FIELD(&rmd.msg_length, RMDM, MCNT, count); \
+ SET_FIELD(&rmd.status, RMDS, OWN, 0); \
RMDSTORE(&rmd, PHYSADDR(s,crda)); \
pktcount++; \
} while (0)
@@ -1102,12 +1170,12 @@
if ((size > 0) && CSR_NRDA(s)) {
target_phys_addr_t nrda = CSR_NRDA(s);
RMDLOAD(&rmd, PHYSADDR(s,nrda));
- if (rmd.rmd1.own) {
+ if (GET_FIELD(rmd.status, RMDS, OWN)) {
crda = nrda;
PCNET_RECV_STORE();
if ((size > 0) && (nrda=CSR_NNRD(s))) {
RMDLOAD(&rmd, PHYSADDR(s,nrda));
- if (rmd.rmd1.own) {
+ if (GET_FIELD(rmd.status, RMDS, OWN)) {
crda = nrda;
PCNET_RECV_STORE();
}
@@ -1119,14 +1187,14 @@
RMDLOAD(&rmd, PHYSADDR(s,crda));
if (size == 0) {
- rmd.rmd1.enp = 1;
- rmd.rmd1.pam = !CSR_PROM(s) && is_padr;
- rmd.rmd1.lafm = !CSR_PROM(s) && is_ladr;
- rmd.rmd1.bam = !CSR_PROM(s) && is_bcast;
+ SET_FIELD(&rmd.status, RMDS, ENP, 1);
+ SET_FIELD(&rmd.status, RMDS, PAM, !CSR_PROM(s) && is_padr);
+ SET_FIELD(&rmd.status, RMDS, LFAM, !CSR_PROM(s) && is_ladr);
+ SET_FIELD(&rmd.status, RMDS, BAM, !CSR_PROM(s) && is_bcast);
} else {
- rmd.rmd1.oflo = 1;
- rmd.rmd1.buff = 1;
- rmd.rmd1.err = 1;
+ SET_FIELD(&rmd.status, RMDS, OFLO, 1);
+ SET_FIELD(&rmd.status, RMDS, BUFF, 1);
+ SET_FIELD(&rmd.status, RMDS, ERR, 1);
}
RMDSTORE(&rmd, PHYSADDR(s,crda));
s->csr[0] |= 0x0400;
@@ -1172,30 +1240,30 @@
if (pcnet_tdte_poll(s)) {
struct pcnet_TMD tmd;
- TMDLOAD(&tmd, PHYSADDR(s,CSR_CXDA(s)));
+ TMDLOAD(&tmd, PHYSADDR(s,CSR_CXDA(s)));
#ifdef PCNET_DEBUG_TMD
printf(" TMDLOAD 0x%08x\n", PHYSADDR(s,CSR_CXDA(s)));
PRINT_TMD(&tmd);
#endif
- if (tmd.tmd1.stp) {
- s->xmit_pos = 0;
- if (!tmd.tmd1.enp) {
- s->phys_mem_read(s->dma_opaque, PHYSADDR(s, tmd.tmd0.tbadr),
- s->buffer, 4096 - tmd.tmd1.bcnt,
- CSR_BSWP(s));
- s->xmit_pos += 4096 - tmd.tmd1.bcnt;
- }
+ if (GET_FIELD(tmd.status, TMDS, STP)) {
+ s->xmit_pos = 0;
+ if (!GET_FIELD(tmd.status, TMDS, ENP)) {
+ int bcnt = 4096 - GET_FIELD(tmd.length, TMDL, BCNT);
+ s->phys_mem_read(s->dma_opaque, PHYSADDR(s, tmd.tbadr),
+ s->buffer, bcnt, CSR_BSWP(s));
+ s->xmit_pos += bcnt;
+ }
xmit_cxda = PHYSADDR(s,CSR_CXDA(s));
}
- if (tmd.tmd1.enp && (s->xmit_pos >= 0)) {
- s->phys_mem_read(s->dma_opaque, PHYSADDR(s, tmd.tmd0.tbadr),
- s->buffer + s->xmit_pos, 4096 - tmd.tmd1.bcnt,
- CSR_BSWP(s));
- s->xmit_pos += 4096 - tmd.tmd1.bcnt;
+ if (GET_FIELD(tmd.status, TMDS, ENP) && (s->xmit_pos >= 0)) {
+ int bcnt = 4096 - GET_FIELD(tmd.length, TMDL, BCNT);
+ s->phys_mem_read(s->dma_opaque, PHYSADDR(s, tmd.tbadr),
+ s->buffer + s->xmit_pos, bcnt, CSR_BSWP(s));
+ s->xmit_pos += bcnt;
#ifdef PCNET_DEBUG
printf("pcnet_transmit size=%d\n", s->xmit_pos);
-#endif
+#endif
if (CSR_LOOP(s))
pcnet_receive(s, s->buffer, s->xmit_pos);
else
@@ -1206,9 +1274,9 @@
s->xmit_pos = -1;
}
- tmd.tmd1.own = 0;
+ SET_FIELD(&tmd.status, TMDS, OWN, 0);
TMDSTORE(&tmd, PHYSADDR(s,CSR_CXDA(s)));
- if (!CSR_TOKINTD(s) || (CSR_LTINTEN(s) && tmd.tmd1.ltint))
+ if (!CSR_TOKINTD(s) || (CSR_LTINTEN(s) && GET_FIELD(tmd.status, TMDS, LTINT)))
s->csr[0] |= 0x0200; /* set TINT */
if (CSR_XMTRC(s)<=1)
@@ -1221,9 +1289,11 @@
} else
if (s->xmit_pos >= 0) {
struct pcnet_TMD tmd;
- TMDLOAD(&tmd, PHYSADDR(s,xmit_cxda));
- tmd.tmd2.buff = tmd.tmd2.uflo = tmd.tmd1.err = 1;
- tmd.tmd1.own = 0;
+ TMDLOAD(&tmd, PHYSADDR(s,xmit_cxda));
+ SET_FIELD(&tmd.misc, TMDM, BUFF, 1);
+ SET_FIELD(&tmd.misc, TMDM, UFLO, 1);
+ SET_FIELD(&tmd.status, TMDS, ERR, 1);
+ SET_FIELD(&tmd.status, TMDS, OWN, 0);
TMDSTORE(&tmd, PHYSADDR(s,xmit_cxda));
s->csr[0] |= 0x0200; /* set TINT */
if (!CSR_DXSUFLO(s)) {
@@ -1870,13 +1940,6 @@
cpu_register_physical_memory(addr, PCNET_PNPMMIO_SIZE, d->mmio_index);
}
-static void pcnet_pci_set_irq_cb(void *opaque, int isr)
-{
- PCNetState *s = opaque;
-
- pci_set_irq(&s->dev, 0, isr);
-}
-
static void pci_physical_memory_write(void *dma_opaque, target_phys_addr_t addr,
uint8_t *buf, int len, int do_bswap)
{
@@ -1889,7 +1952,7 @@
cpu_physical_memory_read(addr, buf, len);
}
-void pci_pcnet_init(PCIBus *bus, NICInfo *nd)
+void pci_pcnet_init(PCIBus *bus, NICInfo *nd, int devfn)
{
PCNetState *d;
uint8_t *pci_conf;
@@ -1900,7 +1963,7 @@
#endif
d = (PCNetState *)pci_register_device(bus, "PCNet", sizeof(PCNetState),
- -1, NULL, NULL);
+ devfn, NULL, NULL);
pci_conf = d->dev.config;
@@ -1931,7 +1994,7 @@
pci_register_io_region((PCIDevice *)d, 1, PCNET_PNPMMIO_SIZE,
PCI_ADDRESS_SPACE_MEM, pcnet_mmio_map);
- d->set_irq_cb = pcnet_pci_set_irq_cb;
+ d->irq = d->dev.irq[0];
d->phys_mem_read = pci_physical_memory_read;
d->phys_mem_write = pci_physical_memory_write;
d->pci_dev = &d->dev;
@@ -1955,15 +2018,8 @@
(CPUWriteMemoryFunc *)&pcnet_ioport_writew,
};
-static void pcnet_sparc_set_irq_cb(void *opaque, int isr)
+void *lance_init(NICInfo *nd, uint32_t leaddr, void *dma_opaque, qemu_irq irq)
{
- PCNetState *s = opaque;
-
- ledma_set_irq(s->dma_opaque, isr);
-}
-
-void *lance_init(NICInfo *nd, uint32_t leaddr, void *dma_opaque)
-{
PCNetState *d;
int lance_io_memory;
@@ -1977,7 +2033,7 @@
d->dma_opaque = dma_opaque;
cpu_register_physical_memory(leaddr, 4, lance_io_memory);
- d->set_irq_cb = pcnet_sparc_set_irq_cb;
+ d->irq = irq;
d->phys_mem_read = ledma_memory_read;
d->phys_mem_write = ledma_memory_write;
Modified: trunk/src/host/qemu-neo1973/hw/pcspk.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/pcspk.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/pcspk.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -92,7 +92,7 @@
}
}
-int pcspk_audio_init(AudioState *audio)
+int pcspk_audio_init(AudioState *audio, qemu_irq *pic)
{
PCSpkState *s = &pcspk_state;
audsettings_t as = {PCSPK_SAMPLE_RATE, 1, AUD_FMT_U8, 0};
Modified: trunk/src/host/qemu-neo1973/hw/pflash_cfi02.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/pflash_cfi02.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/pflash_cfi02.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -91,7 +91,7 @@
uint32_t ret;
uint8_t *p;
- DPRINTF("%s: offset %08x\n", __func__, offset);
+ DPRINTF("%s: offset " TARGET_FMT_lx "\n", __func__, offset);
ret = -1;
offset -= pfl->base;
boff = offset & 0xFF;
@@ -161,7 +161,7 @@
default:
goto flash_read;
}
- DPRINTF("%s: ID %d %x\n", __func__, boff, ret);
+ DPRINTF("%s: ID " TARGET_FMT_ld " %x\n", __func__, boff, ret);
break;
case 0xA0:
case 0x10:
@@ -208,18 +208,23 @@
/* WARNING: when the memory area is in ROMD mode, the offset is a
ram offset, not a physical address */
- if (pfl->wcycle == 0)
- offset -= (target_ulong)(long)pfl->storage;
- else
- offset -= pfl->base;
-
cmd = value;
- DPRINTF("%s: offset %08x %08x %d\n", __func__, offset, value, width);
if (pfl->cmd != 0xA0 && cmd == 0xF0) {
+#if 0
DPRINTF("%s: flash reset asked (%02x %02x)\n",
__func__, pfl->cmd, cmd);
+#endif
goto reset_flash;
}
+ DPRINTF("%s: offset " TARGET_FMT_lx " %08x %d %d\n", __func__,
+ offset, value, width, pfl->wcycle);
+ if (pfl->wcycle == 0)
+ offset -= (target_ulong)(long)pfl->storage;
+ else
+ offset -= pfl->base;
+
+ DPRINTF("%s: offset " TARGET_FMT_lx " %08x %d\n", __func__,
+ offset, value, width);
/* Set the device in I/O access mode */
cpu_register_physical_memory(pfl->base, pfl->total_len, pfl->fl_mem);
boff = offset & (pfl->sector_len - 1);
@@ -239,7 +244,7 @@
return;
}
if (boff != 0x555 || cmd != 0xAA) {
- DPRINTF("%s: unlock0 failed %04x %02x %04x\n",
+ DPRINTF("%s: unlock0 failed " TARGET_FMT_lx " %02x %04x\n",
__func__, boff, cmd, 0x555);
goto reset_flash;
}
@@ -249,7 +254,8 @@
/* We started an unlock sequence */
check_unlock1:
if (boff != 0x2AA || cmd != 0x55) {
- DPRINTF("%s: unlock1 failed %04x %02x\n", __func__, boff, cmd);
+ DPRINTF("%s: unlock1 failed " TARGET_FMT_lx " %02x\n", __func__,
+ boff, cmd);
goto reset_flash;
}
DPRINTF("%s: unlock sequence done\n", __func__);
@@ -257,7 +263,8 @@
case 2:
/* We finished an unlock sequence */
if (!pfl->bypass && boff != 0x555) {
- DPRINTF("%s: command failed %04x %02x\n", __func__, boff, cmd);
+ DPRINTF("%s: command failed " TARGET_FMT_lx " %02x\n", __func__,
+ boff, cmd);
goto reset_flash;
}
switch (cmd) {
@@ -281,7 +288,7 @@
/* We need another unlock sequence */
goto check_unlock0;
case 0xA0:
- DPRINTF("%s: write data offset %08x %08x %d\n",
+ DPRINTF("%s: write data offset " TARGET_FMT_lx " %08x %d\n",
__func__, offset, value, width);
p = pfl->storage;
switch (width) {
@@ -352,7 +359,7 @@
switch (cmd) {
case 0x10:
if (boff != 0x555) {
- DPRINTF("%s: chip erase: invalid address %04x\n",
+ DPRINTF("%s: chip erase: invalid address " TARGET_FMT_lx "\n",
__func__, offset);
goto reset_flash;
}
@@ -369,7 +376,8 @@
/* Sector erase */
p = pfl->storage;
offset &= ~(pfl->sector_len - 1);
- DPRINTF("%s: start sector erase at %08x\n", __func__, offset);
+ DPRINTF("%s: start sector erase at " TARGET_FMT_lx "\n", __func__,
+ offset);
memset(p + offset, 0xFF, pfl->sector_len);
pflash_update(pfl, offset, pfl->sector_len);
pfl->status = 0x00;
@@ -412,10 +420,8 @@
/* Reset flash */
reset_flash:
- if (pfl->wcycle != 0) {
- cpu_register_physical_memory(pfl->base, pfl->total_len,
- pfl->off | IO_MEM_ROMD | pfl->fl_mem);
- }
+ cpu_register_physical_memory(pfl->base, pfl->total_len,
+ pfl->off | IO_MEM_ROMD | pfl->fl_mem);
pfl->bypass = 0;
pfl->wcycle = 0;
pfl->cmd = 0;
@@ -526,14 +532,17 @@
total_len = sector_len * nb_blocs;
/* XXX: to be fixed */
+#if 0
if (total_len != (8 * 1024 * 1024) && total_len != (16 * 1024 * 1024) &&
total_len != (32 * 1024 * 1024) && total_len != (64 * 1024 * 1024))
return NULL;
+#endif
pfl = qemu_mallocz(sizeof(pflash_t));
if (pfl == NULL)
return NULL;
pfl->storage = phys_ram_base + off;
- pfl->fl_mem = cpu_register_io_memory(0, pflash_read_ops, pflash_write_ops, pfl);
+ pfl->fl_mem = cpu_register_io_memory(0, pflash_read_ops, pflash_write_ops,
+ pfl);
pfl->off = off;
cpu_register_physical_memory(base, total_len,
off | pfl->fl_mem | IO_MEM_ROMD);
@@ -609,7 +618,9 @@
pfl->cfi_table[0x28] = 0x02;
pfl->cfi_table[0x29] = 0x00;
/* Max number of bytes in multi-bytes write */
- pfl->cfi_table[0x2A] = 0x05;
+ /* XXX: disable buffered write as it's not supported */
+ // pfl->cfi_table[0x2A] = 0x05;
+ pfl->cfi_table[0x2A] = 0x00;
pfl->cfi_table[0x2B] = 0x00;
/* Number of erase block regions (uniform) */
pfl->cfi_table[0x2C] = 0x01;
Modified: trunk/src/host/qemu-neo1973/hw/piix_pci.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/piix_pci.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/piix_pci.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -40,7 +40,7 @@
return s->config_reg;
}
-static void piix3_set_irq(void *pic, int irq_num, int level);
+static void piix3_set_irq(qemu_irq *pic, int irq_num, int level);
/* return the global irq number corresponding to a given device irq
pin. We could also use the bus number to have a more precise
@@ -155,14 +155,14 @@
return 0;
}
-PCIBus *i440fx_init(PCIDevice **pi440fx_state)
+PCIBus *i440fx_init(PCIDevice **pi440fx_state, qemu_irq *pic)
{
PCIBus *b;
PCIDevice *d;
I440FXState *s;
s = qemu_mallocz(sizeof(I440FXState));
- b = pci_register_bus(piix3_set_irq, pci_slot_get_pirq, NULL, 0, 4);
+ b = pci_register_bus(piix3_set_irq, pci_slot_get_pirq, pic, 0, 4);
s->bus = b;
register_ioport_write(0xcf8, 4, 4, i440fx_addr_writel, s);
@@ -196,14 +196,15 @@
/* PIIX3 PCI to ISA bridge */
-static PCIDevice *piix3_dev;
+PCIDevice *piix3_dev;
+PCIDevice *piix4_dev;
/* just used for simpler irq handling. */
#define PCI_IRQ_WORDS ((PCI_DEVICES_MAX + 31) / 32)
static int pci_irq_levels[4];
-static void piix3_set_irq(void *pic, int irq_num, int level)
+static void piix3_set_irq(qemu_irq *pic, int irq_num, int level)
{
int i, pic_irq, pic_level;
@@ -220,7 +221,7 @@
if (pic_irq == piix3_dev->config[0x60 + i])
pic_level |= pci_irq_levels[i];
}
- pic_set_irq(pic_irq, pic_level);
+ qemu_set_irq(pic[pic_irq], pic_level);
}
}
@@ -245,6 +246,42 @@
pci_conf[0x80] = 0x00;
pci_conf[0x82] = 0x00;
pci_conf[0xa0] = 0x08;
+ pci_conf[0xa2] = 0x00;
+ pci_conf[0xa3] = 0x00;
+ pci_conf[0xa4] = 0x00;
+ pci_conf[0xa5] = 0x00;
+ pci_conf[0xa6] = 0x00;
+ pci_conf[0xa7] = 0x00;
+ pci_conf[0xa8] = 0x0f;
+ pci_conf[0xaa] = 0x00;
+ pci_conf[0xab] = 0x00;
+ pci_conf[0xac] = 0x00;
+ pci_conf[0xae] = 0x00;
+}
+
+static void piix4_reset(PCIDevice *d)
+{
+ uint8_t *pci_conf = d->config;
+
+ pci_conf[0x04] = 0x07; // master, memory and I/O
+ pci_conf[0x05] = 0x00;
+ pci_conf[0x06] = 0x00;
+ pci_conf[0x07] = 0x02; // PCI_status_devsel_medium
+ pci_conf[0x4c] = 0x4d;
+ pci_conf[0x4e] = 0x03;
+ pci_conf[0x4f] = 0x00;
+ pci_conf[0x60] = 0x0a; // PCI A -> IRQ 10
+ pci_conf[0x61] = 0x0a; // PCI B -> IRQ 10
+ pci_conf[0x62] = 0x0b; // PCI C -> IRQ 11
+ pci_conf[0x63] = 0x0b; // PCI D -> IRQ 11
+ pci_conf[0x69] = 0x02;
+ pci_conf[0x70] = 0x80;
+ pci_conf[0x76] = 0x0c;
+ pci_conf[0x77] = 0x0c;
+ pci_conf[0x78] = 0x02;
+ pci_conf[0x79] = 0x00;
+ pci_conf[0x80] = 0x00;
+ pci_conf[0x82] = 0x00;
pci_conf[0xa0] = 0x08;
pci_conf[0xa2] = 0x00;
pci_conf[0xa3] = 0x00;
@@ -273,13 +310,38 @@
return pci_device_load(d, f);
}
-int piix3_init(PCIBus *bus)
+int piix_init(PCIBus *bus, int devfn)
{
PCIDevice *d;
uint8_t *pci_conf;
+ d = pci_register_device(bus, "PIIX", sizeof(PCIDevice),
+ devfn, NULL, NULL);
+ register_savevm("PIIX", 0, 2, piix_save, piix_load, d);
+
+ piix3_dev = d;
+ pci_conf = d->config;
+
+ pci_conf[0x00] = 0x86; // Intel
+ pci_conf[0x01] = 0x80;
+ pci_conf[0x02] = 0x2E; // 82371FB PIIX PCI-to-ISA bridge
+ pci_conf[0x03] = 0x12;
+ pci_conf[0x08] = 0x02; // Step A1
+ pci_conf[0x0a] = 0x01; // class_sub = PCI_ISA
+ pci_conf[0x0b] = 0x06; // class_base = PCI_bridge
+ pci_conf[0x0e] = 0x80; // header_type = PCI_multifunction, generic
+
+ piix3_reset(d);
+ return d->devfn;
+}
+
+int piix3_init(PCIBus *bus, int devfn)
+{
+ PCIDevice *d;
+ uint8_t *pci_conf;
+
d = pci_register_device(bus, "PIIX3", sizeof(PCIDevice),
- -1, NULL, NULL);
+ devfn, NULL, NULL);
register_savevm("PIIX3", 0, 2, piix_save, piix_load, d);
piix3_dev = d;
@@ -296,3 +358,27 @@
piix3_reset(d);
return d->devfn;
}
+
+int piix4_init(PCIBus *bus, int devfn)
+{
+ PCIDevice *d;
+ uint8_t *pci_conf;
+
+ d = pci_register_device(bus, "PIIX4", sizeof(PCIDevice),
+ devfn, NULL, NULL);
+ register_savevm("PIIX4", 0, 2, piix_save, piix_load, d);
+
+ piix4_dev = d;
+ pci_conf = d->config;
+
+ pci_conf[0x00] = 0x86; // Intel
+ pci_conf[0x01] = 0x80;
+ pci_conf[0x02] = 0x10; // 82371AB/EB/MB PIIX4 PCI-to-ISA bridge
+ pci_conf[0x03] = 0x71;
+ pci_conf[0x0a] = 0x01; // class_sub = PCI_ISA
+ pci_conf[0x0b] = 0x06; // class_base = PCI_bridge
+ pci_conf[0x0e] = 0x80; // header_type = PCI_multifunction, generic
+
+ piix4_reset(d);
+ return d->devfn;
+}
Modified: trunk/src/host/qemu-neo1973/hw/pl011.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/pl011.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/pl011.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -27,8 +27,7 @@
int read_count;
int read_trigger;
CharDriverState *chr;
- void *pic;
- int irq;
+ qemu_irq irq;
} pl011_state;
#define PL011_INT_TX 0x20
@@ -47,7 +46,7 @@
uint32_t flags;
flags = s->int_level & s->int_enabled;
- pic_set_irq_new(s->pic, s->irq, flags != 0);
+ qemu_set_irq(s->irq, flags != 0);
}
static uint32_t pl011_read(void *opaque, target_phys_addr_t offset)
@@ -224,7 +223,7 @@
pl011_write
};
-void pl011_init(uint32_t base, void *pic, int irq,
+void pl011_init(uint32_t base, qemu_irq irq,
CharDriverState *chr)
{
int iomemtype;
@@ -235,7 +234,6 @@
pl011_writefn, s);
cpu_register_physical_memory(base, 0x00000fff, iomemtype);
s->base = base;
- s->pic = pic;
s->irq = irq;
s->chr = chr;
s->read_trigger = 1;
@@ -243,8 +241,8 @@
s->cr = 0x300;
s->flags = 0x90;
if (chr){
- qemu_chr_add_read_handler(chr, pl011_can_recieve, pl011_recieve, s);
- qemu_chr_add_event_handler(chr, pl011_event);
+ qemu_chr_add_handlers(chr, pl011_can_recieve, pl011_recieve,
+ pl011_event, s);
}
/* ??? Save/restore. */
}
Modified: trunk/src/host/qemu-neo1973/hw/pl050.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/pl050.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/pl050.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -1,7 +1,7 @@
/*
* Arm PrimeCell PL050 Keyboard / Mouse Interface
*
- * Copyright (c) 2006 CodeSourcery.
+ * Copyright (c) 2006-2007 CodeSourcery.
* Written by Paul Brook
*
* This code is licenced under the GPL.
@@ -15,12 +15,19 @@
uint32_t cr;
uint32_t clk;
uint32_t last;
- void *pic;
int pending;
- int irq;
+ qemu_irq irq;
int is_mouse;
} pl050_state;
+#define PL050_TXEMPTY (1 << 6)
+#define PL050_TXBUSY (1 << 5)
+#define PL050_RXFULL (1 << 4)
+#define PL050_RXBUSY (1 << 3)
+#define PL050_RXPARITY (1 << 2)
+#define PL050_KMIC (1 << 1)
+#define PL050_KMID (1 << 0)
+
static const unsigned char pl050_id[] =
{ 0x50, 0x10, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
@@ -32,7 +39,7 @@
s->pending = level;
raise = (s->pending && (s->cr & 0x10) != 0)
|| (s->cr & 0x08) != 0;
- pic_set_irq_new(s->pic, s->irq, raise);
+ qemu_set_irq(s->irq, raise);
}
static uint32_t pl050_read(void *opaque, target_phys_addr_t offset)
@@ -46,11 +53,22 @@
case 0: /* KMICR */
return s->cr;
case 1: /* KMISTAT */
- /* KMIC and KMID bits not implemented. */
- if (s->pending) {
- return 0x10;
- } else {
- return 0;
+ {
+ uint8_t val;
+ uint32_t stat;
+
+ val = s->last;
+ val = val ^ (val >> 4);
+ val = val ^ (val >> 2);
+ val = (val ^ (val >> 1)) & 1;
+
+ stat = PL050_TXEMPTY;
+ if (val)
+ stat |= PL050_RXPARITY;
+ if (s->pending)
+ stat |= PL050_RXFULL;
+
+ return stat;
}
case 2: /* KMIDATA */
if (s->pending)
@@ -105,7 +123,7 @@
pl050_write
};
-void pl050_init(uint32_t base, void *pic, int irq, int is_mouse)
+void pl050_init(uint32_t base, qemu_irq irq, int is_mouse)
{
int iomemtype;
pl050_state *s;
@@ -115,7 +133,6 @@
pl050_writefn, s);
cpu_register_physical_memory(base, 0x00000fff, iomemtype);
s->base = base;
- s->pic = pic;
s->irq = irq;
s->is_mouse = is_mouse;
if (is_mouse)
Modified: trunk/src/host/qemu-neo1973/hw/pl080.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/pl080.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/pl080.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -49,8 +49,7 @@
int nchannels;
/* Flag to avoid recursive DMA invocations. */
int running;
- void *pic;
- int irq;
+ qemu_irq irq;
} pl080_state;
static const unsigned char pl080_id[] =
@@ -63,9 +62,9 @@
{
if ((s->tc_int & s->tc_mask)
|| (s->err_int & s->err_mask))
- pic_set_irq_new(s->pic, s->irq, 1);
+ qemu_irq_raise(s->irq);
else
- pic_set_irq_new(s->pic, s->irq, 1);
+ qemu_irq_lower(s->irq);
}
static void pl080_run(pl080_state *s)
@@ -325,7 +324,7 @@
/* The PL080 and PL081 are the same except for the number of channels
they implement (8 and 2 respectively). */
-void *pl080_init(uint32_t base, void *pic, int irq, int nchannels)
+void *pl080_init(uint32_t base, qemu_irq irq, int nchannels)
{
int iomemtype;
pl080_state *s;
@@ -335,7 +334,6 @@
pl080_writefn, s);
cpu_register_physical_memory(base, 0x00000fff, iomemtype);
s->base = base;
- s->pic = pic;
s->irq = irq;
s->nchannels = nchannels;
/* ??? Save/restore. */
Modified: trunk/src/host/qemu-neo1973/hw/pl110.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/pl110.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/pl110.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -29,7 +29,6 @@
DisplayState *ds;
/* The Versatile/PB uses a slightly modified PL110 controller. */
int versatile;
- void *pic;
uint32_t timing[4];
uint32_t cr;
uint32_t upbase;
@@ -42,7 +41,7 @@
int invalidate;
uint32_t pallette[256];
uint32_t raw_pallette[128];
- int irq;
+ qemu_irq irq;
} pl110_state;
static const unsigned char pl110_id[] =
@@ -399,7 +398,7 @@
pl110_write
};
-void *pl110_init(DisplayState *ds, uint32_t base, void *pic, int irq,
+void *pl110_init(DisplayState *ds, uint32_t base, qemu_irq irq,
int versatile)
{
pl110_state *s;
@@ -412,7 +411,6 @@
s->base = base;
s->ds = ds;
s->versatile = versatile;
- s->pic = pic;
s->irq = irq;
graphic_console_init(ds, pl110_update_display, pl110_invalidate_display,
NULL, s);
Added: trunk/src/host/qemu-neo1973/hw/pl181.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/pl181.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/pl181.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,443 @@
+/*
+ * Arm PrimeCell PL181 MultiMedia Card Interface
+ *
+ * Copyright (c) 2007 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licenced under the GPL.
+ */
+
+#include "vl.h"
+#include "sd.h"
+
+//#define DEBUG_PL181 1
+
+#ifdef DEBUG_PL181
+#define DPRINTF(fmt, args...) \
+do { printf("pl181: " fmt , ##args); } while (0)
+#else
+#define DPRINTF(fmt, args...) do {} while(0)
+#endif
+
+#define PL181_FIFO_LEN 16
+
+typedef struct {
+ SDState *card;
+ uint32_t base;
+ uint32_t clock;
+ uint32_t power;
+ uint32_t cmdarg;
+ uint32_t cmd;
+ uint32_t datatimer;
+ uint32_t datalength;
+ uint32_t respcmd;
+ uint32_t response[4];
+ uint32_t datactrl;
+ uint32_t datacnt;
+ uint32_t status;
+ uint32_t mask[2];
+ uint32_t fifocnt;
+ int fifo_pos;
+ int fifo_len;
+ uint32_t fifo[PL181_FIFO_LEN];
+ qemu_irq irq[2];
+} pl181_state;
+
+#define PL181_CMD_INDEX 0x3f
+#define PL181_CMD_RESPONSE (1 << 6)
+#define PL181_CMD_LONGRESP (1 << 7)
+#define PL181_CMD_INTERRUPT (1 << 8)
+#define PL181_CMD_PENDING (1 << 9)
+#define PL181_CMD_ENABLE (1 << 10)
+
+#define PL181_DATA_ENABLE (1 << 0)
+#define PL181_DATA_DIRECTION (1 << 1)
+#define PL181_DATA_MODE (1 << 2)
+#define PL181_DATA_DMAENABLE (1 << 3)
+
+#define PL181_STATUS_CMDCRCFAIL (1 << 0)
+#define PL181_STATUS_DATACRCFAIL (1 << 1)
+#define PL181_STATUS_CMDTIMEOUT (1 << 2)
+#define PL181_STATUS_DATATIMEOUT (1 << 3)
+#define PL181_STATUS_TXUNDERRUN (1 << 4)
+#define PL181_STATUS_RXOVERRUN (1 << 5)
+#define PL181_STATUS_CMDRESPEND (1 << 6)
+#define PL181_STATUS_CMDSENT (1 << 7)
+#define PL181_STATUS_DATAEND (1 << 8)
+#define PL181_STATUS_DATABLOCKEND (1 << 10)
+#define PL181_STATUS_CMDACTIVE (1 << 11)
+#define PL181_STATUS_TXACTIVE (1 << 12)
+#define PL181_STATUS_RXACTIVE (1 << 13)
+#define PL181_STATUS_TXFIFOHALFEMPTY (1 << 14)
+#define PL181_STATUS_RXFIFOHALFFULL (1 << 15)
+#define PL181_STATUS_TXFIFOFULL (1 << 16)
+#define PL181_STATUS_RXFIFOFULL (1 << 17)
+#define PL181_STATUS_TXFIFOEMPTY (1 << 18)
+#define PL181_STATUS_RXFIFOEMPTY (1 << 19)
+#define PL181_STATUS_TXDATAAVLBL (1 << 20)
+#define PL181_STATUS_RXDATAAVLBL (1 << 21)
+
+#define PL181_STATUS_TX_FIFO (PL181_STATUS_TXACTIVE \
+ |PL181_STATUS_TXFIFOHALFEMPTY \
+ |PL181_STATUS_TXFIFOFULL \
+ |PL181_STATUS_TXFIFOEMPTY \
+ |PL181_STATUS_TXDATAAVLBL)
+#define PL181_STATUS_RX_FIFO (PL181_STATUS_RXACTIVE \
+ |PL181_STATUS_RXFIFOHALFFULL \
+ |PL181_STATUS_RXFIFOFULL \
+ |PL181_STATUS_RXFIFOEMPTY \
+ |PL181_STATUS_RXDATAAVLBL)
+
+static const unsigned char pl181_id[] =
+{ 0x81, 0x11, 0x04, 0x00, 0x0d, 0xf0, 0x05, 0xb1 };
+
+static void pl181_update(pl181_state *s)
+{
+ int i;
+ for (i = 0; i < 2; i++) {
+ qemu_set_irq(s->irq[i], (s->status & s->mask[i]) != 0);
+ }
+}
+
+static void pl181_fifo_push(pl181_state *s, uint32_t value)
+{
+ int n;
+
+ if (s->fifo_len == PL181_FIFO_LEN) {
+ fprintf(stderr, "pl181: FIFO overflow\n");
+ return;
+ }
+ n = (s->fifo_pos + s->fifo_len) & (PL181_FIFO_LEN - 1);
+ s->fifo_len++;
+ s->fifo[n] = value;
+ DPRINTF("FIFO push %08x\n", (int)value);
+}
+
+static uint32_t pl181_fifo_pop(pl181_state *s)
+{
+ uint32_t value;
+
+ if (s->fifo_len == 0) {
+ fprintf(stderr, "pl181: FIFO underflow\n");
+ return 0;
+ }
+ value = s->fifo[s->fifo_pos];
+ s->fifo_len--;
+ s->fifo_pos = (s->fifo_pos + 1) & (PL181_FIFO_LEN - 1);
+ DPRINTF("FIFO pop %08x\n", (int)value);
+ return value;
+}
+
+static void pl181_send_command(pl181_state *s)
+{
+ struct sd_request_s request;
+ uint8_t response[16];
+ int rlen;
+
+ request.cmd = s->cmd & PL181_CMD_INDEX;
+ request.arg = s->cmdarg;
+ DPRINTF("Command %d %08x\n", request.cmd, request.arg);
+ rlen = sd_do_command(s->card, &request, response);
+ if (rlen < 0)
+ goto error;
+ if (s->cmd & PL181_CMD_RESPONSE) {
+#define RWORD(n) ((response[n] << 24) | (response[n + 1] << 16) \
+ | (response[n + 2] << 8) | response[n + 3])
+ if (rlen == 0 || (rlen == 4 && (s->cmd & PL181_CMD_LONGRESP)))
+ goto error;
+ if (rlen != 4 && rlen != 16)
+ goto error;
+ s->response[0] = RWORD(0);
+ if (rlen == 4) {
+ s->response[1] = s->response[2] = s->response[3] = 0;
+ } else {
+ s->response[1] = RWORD(4);
+ s->response[2] = RWORD(8);
+ s->response[3] = RWORD(12) & ~1;
+ }
+ DPRINTF("Response recieved\n");
+ s->status |= PL181_STATUS_CMDRESPEND;
+#undef RWORD
+ } else {
+ DPRINTF("Command sent\n");
+ s->status |= PL181_STATUS_CMDSENT;
+ }
+ return;
+
+error:
+ DPRINTF("Timeout\n");
+ s->status |= PL181_STATUS_CMDTIMEOUT;
+}
+
+/* Transfer data between teh card and the FIFO. This is complicated by
+ the FIFO holding 32-bit words and the card taking data in single byte
+ chunks. FIFO bytes are transferred in little-endian order. */
+
+static void pl181_fifo_run(pl181_state *s)
+{
+ uint32_t bits;
+ uint32_t value;
+ int n;
+ int limit;
+ int is_read;
+
+ is_read = (s->datactrl & PL181_DATA_DIRECTION) != 0;
+ if (s->datacnt != 0 && (!is_read || sd_data_ready(s->card))) {
+ limit = is_read ? PL181_FIFO_LEN : 0;
+ n = 0;
+ value = 0;
+ while (s->datacnt && s->fifo_len != limit) {
+ if (is_read) {
+ value |= (uint32_t)sd_read_data(s->card) << (n * 8);
+ n++;
+ if (n == 4) {
+ pl181_fifo_push(s, value);
+ value = 0;
+ n = 0;
+ }
+ } else {
+ if (n == 0) {
+ value = pl181_fifo_pop(s);
+ n = 4;
+ }
+ sd_write_data(s->card, value & 0xff);
+ value >>= 8;
+ n--;
+ }
+ s->datacnt--;
+ }
+ if (n && is_read) {
+ pl181_fifo_push(s, value);
+ }
+ }
+ s->status &= ~(PL181_STATUS_RX_FIFO | PL181_STATUS_TX_FIFO);
+ if (s->datacnt == 0) {
+ s->status |= PL181_STATUS_DATAEND;
+ /* HACK: */
+ s->status |= PL181_STATUS_DATABLOCKEND;
+ DPRINTF("Transfer Complete\n");
+ }
+ if (s->datacnt == 0 && s->fifocnt == 0) {
+ s->datactrl &= ~PL181_DATA_ENABLE;
+ DPRINTF("Data engine idle\n");
+ } else {
+ /* Update FIFO bits. */
+ bits = PL181_STATUS_TXACTIVE | PL181_STATUS_RXACTIVE;
+ if (s->fifo_len == 0) {
+ bits |= PL181_STATUS_TXFIFOEMPTY;
+ bits |= PL181_STATUS_RXFIFOEMPTY;
+ } else {
+ bits |= PL181_STATUS_TXDATAAVLBL;
+ bits |= PL181_STATUS_RXDATAAVLBL;
+ }
+ if (s->fifo_len == 16) {
+ bits |= PL181_STATUS_TXFIFOFULL;
+ bits |= PL181_STATUS_RXFIFOFULL;
+ }
+ if (s->fifo_len <= 8) {
+ bits |= PL181_STATUS_TXFIFOHALFEMPTY;
+ }
+ if (s->fifo_len >= 8) {
+ bits |= PL181_STATUS_RXFIFOHALFFULL;
+ }
+ if (s->datactrl & PL181_DATA_DIRECTION) {
+ bits &= PL181_STATUS_RX_FIFO;
+ } else {
+ bits &= PL181_STATUS_TX_FIFO;
+ }
+ s->status |= bits;
+ }
+}
+
+static uint32_t pl181_read(void *opaque, target_phys_addr_t offset)
+{
+ pl181_state *s = (pl181_state *)opaque;
+
+ offset -= s->base;
+ if (offset >= 0xfe0 && offset < 0x1000) {
+ return pl181_id[(offset - 0xfe0) >> 2];
+ }
+ switch (offset) {
+ case 0x00: /* Power */
+ return s->power;
+ case 0x04: /* Clock */
+ return s->clock;
+ case 0x08: /* Argument */
+ return s->cmdarg;
+ case 0x0c: /* Command */
+ return s->cmd;
+ case 0x10: /* RespCmd */
+ return s->respcmd;
+ case 0x14: /* Response0 */
+ return s->response[0];
+ case 0x18: /* Response1 */
+ return s->response[1];
+ case 0x1c: /* Response2 */
+ return s->response[2];
+ case 0x20: /* Response3 */
+ return s->response[3];
+ case 0x24: /* DataTimer */
+ return s->datatimer;
+ case 0x28: /* DataLength */
+ return s->datalength;
+ case 0x2c: /* DataCtrl */
+ return s->datactrl;
+ case 0x30: /* DataCnt */
+ return s->datacnt;
+ case 0x34: /* Status */
+ return s->status;
+ case 0x3c: /* Mask0 */
+ return s->mask[0];
+ case 0x40: /* Mask1 */
+ return s->mask[1];
+ case 0x48: /* FifoCnt */
+ return s->fifocnt;
+ case 0x80: case 0x84: case 0x88: case 0x8c: /* FifoData */
+ case 0x90: case 0x94: case 0x98: case 0x9c:
+ case 0xa0: case 0xa4: case 0xa8: case 0xac:
+ case 0xb0: case 0xb4: case 0xb8: case 0xbc:
+ if (s->fifocnt == 0) {
+ fprintf(stderr, "pl181: Unexpected FIFO read\n");
+ return 0;
+ } else {
+ uint32_t value;
+ s->fifocnt--;
+ value = pl181_fifo_pop(s);
+ pl181_fifo_run(s);
+ pl181_update(s);
+ return value;
+ }
+ default:
+ cpu_abort (cpu_single_env, "pl181_read: Bad offset %x\n", offset);
+ return 0;
+ }
+}
+
+static void pl181_write(void *opaque, target_phys_addr_t offset,
+ uint32_t value)
+{
+ pl181_state *s = (pl181_state *)opaque;
+
+ offset -= s->base;
+ switch (offset) {
+ case 0x00: /* Power */
+ s->power = value & 0xff;
+ break;
+ case 0x04: /* Clock */
+ s->clock = value & 0xff;
+ break;
+ case 0x08: /* Argument */
+ s->cmdarg = value;
+ break;
+ case 0x0c: /* Command */
+ s->cmd = value;
+ if (s->cmd & PL181_CMD_ENABLE) {
+ if (s->cmd & PL181_CMD_INTERRUPT) {
+ fprintf(stderr, "pl181: Interrupt mode not implemented\n");
+ abort();
+ } if (s->cmd & PL181_CMD_PENDING) {
+ fprintf(stderr, "pl181: Pending commands not implemented\n");
+ abort();
+ } else {
+ pl181_send_command(s);
+ pl181_fifo_run(s);
+ }
+ /* The command has completed one way or the other. */
+ s->cmd &= ~PL181_CMD_ENABLE;
+ }
+ break;
+ case 0x24: /* DataTimer */
+ s->datatimer = value;
+ break;
+ case 0x28: /* DataLength */
+ s->datalength = value & 0xffff;
+ break;
+ case 0x2c: /* DataCtrl */
+ s->datactrl = value & 0xff;
+ if (value & PL181_DATA_ENABLE) {
+ s->datacnt = s->datalength;
+ s->fifocnt = (s->datalength + 3) >> 2;
+ pl181_fifo_run(s);
+ }
+ break;
+ case 0x38: /* Clear */
+ s->status &= ~(value & 0x7ff);
+ break;
+ case 0x3c: /* Mask0 */
+ s->mask[0] = value;
+ break;
+ case 0x40: /* Mask1 */
+ s->mask[1] = value;
+ break;
+ case 0x80: case 0x84: case 0x88: case 0x8c: /* FifoData */
+ case 0x90: case 0x94: case 0x98: case 0x9c:
+ case 0xa0: case 0xa4: case 0xa8: case 0xac:
+ case 0xb0: case 0xb4: case 0xb8: case 0xbc:
+ if (s->fifocnt == 0) {
+ fprintf(stderr, "pl181: Unexpected FIFO write\n");
+ } else {
+ s->fifocnt--;
+ pl181_fifo_push(s, value);
+ pl181_fifo_run(s);
+ }
+ break;
+ default:
+ cpu_abort (cpu_single_env, "pl181_write: Bad offset %x\n", offset);
+ }
+ pl181_update(s);
+}
+
+static CPUReadMemoryFunc *pl181_readfn[] = {
+ pl181_read,
+ pl181_read,
+ pl181_read
+};
+
+static CPUWriteMemoryFunc *pl181_writefn[] = {
+ pl181_write,
+ pl181_write,
+ pl181_write
+};
+
+static void pl181_reset(void *opaque)
+{
+ pl181_state *s = (pl181_state *)opaque;
+
+ s->power = 0;
+ s->cmdarg = 0;
+ s->cmd = 0;
+ s->datatimer = 0;
+ s->datalength = 0;
+ s->respcmd = 0;
+ s->response[0] = 0;
+ s->response[1] = 0;
+ s->response[2] = 0;
+ s->response[3] = 0;
+ s->datatimer = 0;
+ s->datalength = 0;
+ s->datactrl = 0;
+ s->datacnt = 0;
+ s->status = 0;
+ s->mask[0] = 0;
+ s->mask[1] = 0;
+ s->fifocnt = 0;
+}
+
+void pl181_init(uint32_t base, BlockDriverState *bd,
+ qemu_irq irq0, qemu_irq irq1)
+{
+ int iomemtype;
+ pl181_state *s;
+
+ s = (pl181_state *)qemu_mallocz(sizeof(pl181_state));
+ iomemtype = cpu_register_io_memory(0, pl181_readfn,
+ pl181_writefn, s);
+ cpu_register_physical_memory(base, 0x00000fff, iomemtype);
+ s->base = base;
+ s->card = sd_init(bd);
+ s->irq[0] = irq0;
+ s->irq[1] = irq1;
+ qemu_register_reset(pl181_reset, s);
+ pl181_reset(s);
+ /* ??? Save/restore. */
+}
Modified: trunk/src/host/qemu-neo1973/hw/pl190.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/pl190.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/pl190.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -17,7 +17,6 @@
#define PL190_NUM_PRIO 17
typedef struct {
- arm_pic_handler handler;
uint32_t base;
DisplayState *ds;
uint32_t level;
@@ -33,9 +32,8 @@
/* Current priority level. */
int priority;
int prev_prio[PL190_NUM_PRIO];
- void *parent;
- int irq;
- int fiq;
+ qemu_irq irq;
+ qemu_irq fiq;
} pl190_state;
static const unsigned char pl190_id[] =
@@ -53,9 +51,9 @@
int set;
set = (level & s->prio_mask[s->priority]) != 0;
- pic_set_irq_new(s->parent, s->irq, set);
+ qemu_set_irq(s->irq, set);
set = ((s->level | s->soft_level) & s->fiq_select) != 0;
- pic_set_irq_new(s->parent, s->fiq, set);
+ qemu_set_irq(s->fiq, set);
}
static void pl190_set_irq(void *opaque, int irq, int level)
@@ -232,21 +230,21 @@
pl190_update_vectors(s);
}
-void *pl190_init(uint32_t base, void *parent, int irq, int fiq)
+qemu_irq *pl190_init(uint32_t base, qemu_irq irq, qemu_irq fiq)
{
pl190_state *s;
+ qemu_irq *qi;
int iomemtype;
s = (pl190_state *)qemu_mallocz(sizeof(pl190_state));
iomemtype = cpu_register_io_memory(0, pl190_readfn,
pl190_writefn, s);
cpu_register_physical_memory(base, 0x00000fff, iomemtype);
- s->handler = pl190_set_irq;
+ qi = qemu_allocate_irqs(pl190_set_irq, s, 32);
s->base = base;
- s->parent = parent;
s->irq = irq;
s->fiq = fiq;
pl190_reset(s);
/* ??? Save/restore. */
- return s;
+ return qi;
}
Modified: trunk/src/host/qemu-neo1973/hw/ppc.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/ppc.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/ppc.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -1,7 +1,7 @@
/*
- * QEMU generic PPC hardware System Emulator
+ * QEMU generic PowerPC hardware System Emulator
*
- * Copyright (c) 2003-2004 Jocelyn Mayer
+ * Copyright (c) 2003-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
@@ -24,10 +24,387 @@
#include "vl.h"
#include "m48t59.h"
+//#define PPC_DEBUG_IRQ
+//#define PPC_DEBUG_TB
+
+extern FILE *logfile;
+extern int loglevel;
+
+void ppc_set_irq (CPUState *env, int n_IRQ, int level)
+{
+ if (level) {
+ env->pending_interrupts |= 1 << n_IRQ;
+ cpu_interrupt(env, CPU_INTERRUPT_HARD);
+ } else {
+ env->pending_interrupts &= ~(1 << n_IRQ);
+ if (env->pending_interrupts == 0)
+ cpu_reset_interrupt(env, CPU_INTERRUPT_HARD);
+ }
+#if defined(PPC_DEBUG_IRQ)
+ if (loglevel & CPU_LOG_INT) {
+ fprintf(logfile, "%s: %p n_IRQ %d level %d => pending %08x req %08x\n",
+ __func__, env, n_IRQ, level,
+ env->pending_interrupts, env->interrupt_request);
+ }
+#endif
+}
+
+/* PowerPC 6xx / 7xx internal IRQ controller */
+static void ppc6xx_set_irq (void *opaque, int pin, int level)
+{
+ CPUState *env = opaque;
+ int cur_level;
+
+#if defined(PPC_DEBUG_IRQ)
+ if (loglevel & CPU_LOG_INT) {
+ fprintf(logfile, "%s: env %p pin %d level %d\n", __func__,
+ env, pin, level);
+ }
+#endif
+ cur_level = (env->irq_input_state >> pin) & 1;
+ /* Don't generate spurious events */
+ if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
+ switch (pin) {
+ case PPC6xx_INPUT_INT:
+ /* Level sensitive - active high */
+#if defined(PPC_DEBUG_IRQ)
+ if (loglevel & CPU_LOG_INT) {
+ fprintf(logfile, "%s: set the external IRQ state to %d\n",
+ __func__, level);
+ }
+#endif
+ ppc_set_irq(env, PPC_INTERRUPT_EXT, level);
+ break;
+ case PPC6xx_INPUT_SMI:
+ /* Level sensitive - active high */
+#if defined(PPC_DEBUG_IRQ)
+ if (loglevel & CPU_LOG_INT) {
+ fprintf(logfile, "%s: set the SMI IRQ state to %d\n",
+ __func__, level);
+ }
+#endif
+ ppc_set_irq(env, PPC_INTERRUPT_SMI, level);
+ break;
+ case PPC6xx_INPUT_MCP:
+ /* Negative edge sensitive */
+ /* XXX: TODO: actual reaction may depends on HID0 status
+ * 603/604/740/750: check HID0[EMCP]
+ */
+ if (cur_level == 1 && level == 0) {
+#if defined(PPC_DEBUG_IRQ)
+ if (loglevel & CPU_LOG_INT) {
+ fprintf(logfile, "%s: raise machine check state\n",
+ __func__);
+ }
+#endif
+ ppc_set_irq(env, PPC_INTERRUPT_MCK, 1);
+ }
+ break;
+ case PPC6xx_INPUT_CKSTP_IN:
+ /* Level sensitive - active low */
+ /* XXX: TODO: relay the signal to CKSTP_OUT pin */
+ if (level) {
+#if defined(PPC_DEBUG_IRQ)
+ if (loglevel & CPU_LOG_INT) {
+ fprintf(logfile, "%s: stop the CPU\n", __func__);
+ }
+#endif
+ env->halted = 1;
+ } else {
+#if defined(PPC_DEBUG_IRQ)
+ if (loglevel & CPU_LOG_INT) {
+ fprintf(logfile, "%s: restart the CPU\n", __func__);
+ }
+#endif
+ env->halted = 0;
+ }
+ break;
+ case PPC6xx_INPUT_HRESET:
+ /* Level sensitive - active low */
+ if (level) {
+#if 0 // XXX: TOFIX
+#if defined(PPC_DEBUG_IRQ)
+ if (loglevel & CPU_LOG_INT) {
+ fprintf(logfile, "%s: reset the CPU\n", __func__);
+ }
+#endif
+ cpu_reset(env);
+#endif
+ }
+ break;
+ case PPC6xx_INPUT_SRESET:
+#if defined(PPC_DEBUG_IRQ)
+ if (loglevel & CPU_LOG_INT) {
+ fprintf(logfile, "%s: set the RESET IRQ state to %d\n",
+ __func__, level);
+ }
+#endif
+ ppc_set_irq(env, PPC_INTERRUPT_RESET, level);
+ break;
+ default:
+ /* Unknown pin - do nothing */
+#if defined(PPC_DEBUG_IRQ)
+ if (loglevel & CPU_LOG_INT) {
+ fprintf(logfile, "%s: unknown IRQ pin %d\n", __func__, pin);
+ }
+#endif
+ return;
+ }
+ if (level)
+ env->irq_input_state |= 1 << pin;
+ else
+ env->irq_input_state &= ~(1 << pin);
+ }
+}
+
+void ppc6xx_irq_init (CPUState *env)
+{
+ env->irq_inputs = (void **)qemu_allocate_irqs(&ppc6xx_set_irq, env, 6);
+}
+
+/* PowerPC 970 internal IRQ controller */
+static void ppc970_set_irq (void *opaque, int pin, int level)
+{
+ CPUState *env = opaque;
+ int cur_level;
+
+#if defined(PPC_DEBUG_IRQ)
+ if (loglevel & CPU_LOG_INT) {
+ fprintf(logfile, "%s: env %p pin %d level %d\n", __func__,
+ env, pin, level);
+ }
+#endif
+ cur_level = (env->irq_input_state >> pin) & 1;
+ /* Don't generate spurious events */
+ if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
+ switch (pin) {
+ case PPC970_INPUT_INT:
+ /* Level sensitive - active high */
+#if defined(PPC_DEBUG_IRQ)
+ if (loglevel & CPU_LOG_INT) {
+ fprintf(logfile, "%s: set the external IRQ state to %d\n",
+ __func__, level);
+ }
+#endif
+ ppc_set_irq(env, PPC_INTERRUPT_EXT, level);
+ break;
+ case PPC970_INPUT_THINT:
+ /* Level sensitive - active high */
+#if defined(PPC_DEBUG_IRQ)
+ if (loglevel & CPU_LOG_INT) {
+ fprintf(logfile, "%s: set the SMI IRQ state to %d\n", __func__,
+ level);
+ }
+#endif
+ ppc_set_irq(env, PPC_INTERRUPT_THERM, level);
+ break;
+ case PPC970_INPUT_MCP:
+ /* Negative edge sensitive */
+ /* XXX: TODO: actual reaction may depends on HID0 status
+ * 603/604/740/750: check HID0[EMCP]
+ */
+ if (cur_level == 1 && level == 0) {
+#if defined(PPC_DEBUG_IRQ)
+ if (loglevel & CPU_LOG_INT) {
+ fprintf(logfile, "%s: raise machine check state\n",
+ __func__);
+ }
+#endif
+ ppc_set_irq(env, PPC_INTERRUPT_MCK, 1);
+ }
+ break;
+ case PPC970_INPUT_CKSTP:
+ /* Level sensitive - active low */
+ /* XXX: TODO: relay the signal to CKSTP_OUT pin */
+ if (level) {
+#if defined(PPC_DEBUG_IRQ)
+ if (loglevel & CPU_LOG_INT) {
+ fprintf(logfile, "%s: stop the CPU\n", __func__);
+ }
+#endif
+ env->halted = 1;
+ } else {
+#if defined(PPC_DEBUG_IRQ)
+ if (loglevel & CPU_LOG_INT) {
+ fprintf(logfile, "%s: restart the CPU\n", __func__);
+ }
+#endif
+ env->halted = 0;
+ }
+ break;
+ case PPC970_INPUT_HRESET:
+ /* Level sensitive - active low */
+ if (level) {
+#if 0 // XXX: TOFIX
+#if defined(PPC_DEBUG_IRQ)
+ if (loglevel & CPU_LOG_INT) {
+ fprintf(logfile, "%s: reset the CPU\n", __func__);
+ }
+#endif
+ cpu_reset(env);
+#endif
+ }
+ break;
+ case PPC970_INPUT_SRESET:
+#if defined(PPC_DEBUG_IRQ)
+ if (loglevel & CPU_LOG_INT) {
+ fprintf(logfile, "%s: set the RESET IRQ state to %d\n",
+ __func__, level);
+ }
+#endif
+ ppc_set_irq(env, PPC_INTERRUPT_RESET, level);
+ break;
+ case PPC970_INPUT_TBEN:
+#if defined(PPC_DEBUG_IRQ)
+ if (loglevel & CPU_LOG_INT) {
+ fprintf(logfile, "%s: set the TBEN state to %d\n", __func__,
+ level);
+ }
+#endif
+ /* XXX: TODO */
+ break;
+ default:
+ /* Unknown pin - do nothing */
+#if defined(PPC_DEBUG_IRQ)
+ if (loglevel & CPU_LOG_INT) {
+ fprintf(logfile, "%s: unknown IRQ pin %d\n", __func__, pin);
+ }
+#endif
+ return;
+ }
+ if (level)
+ env->irq_input_state |= 1 << pin;
+ else
+ env->irq_input_state &= ~(1 << pin);
+ }
+}
+
+void ppc970_irq_init (CPUState *env)
+{
+ env->irq_inputs = (void **)qemu_allocate_irqs(&ppc970_set_irq, env, 7);
+}
+
+/* PowerPC 405 internal IRQ controller */
+static void ppc405_set_irq (void *opaque, int pin, int level)
+{
+ CPUState *env = opaque;
+ int cur_level;
+
+#if defined(PPC_DEBUG_IRQ)
+ if (loglevel & CPU_LOG_INT) {
+ fprintf(logfile, "%s: env %p pin %d level %d\n", __func__,
+ env, pin, level);
+ }
+#endif
+ cur_level = (env->irq_input_state >> pin) & 1;
+ /* Don't generate spurious events */
+ if ((cur_level == 1 && level == 0) || (cur_level == 0 && level != 0)) {
+ switch (pin) {
+ case PPC405_INPUT_RESET_SYS:
+ if (level) {
+#if defined(PPC_DEBUG_IRQ)
+ if (loglevel & CPU_LOG_INT) {
+ fprintf(logfile, "%s: reset the PowerPC system\n",
+ __func__);
+ }
+#endif
+ ppc40x_system_reset(env);
+ }
+ break;
+ case PPC405_INPUT_RESET_CHIP:
+ if (level) {
+#if defined(PPC_DEBUG_IRQ)
+ if (loglevel & CPU_LOG_INT) {
+ fprintf(logfile, "%s: reset the PowerPC chip\n", __func__);
+ }
+#endif
+ ppc40x_chip_reset(env);
+ }
+ break;
+ /* No break here */
+ case PPC405_INPUT_RESET_CORE:
+ /* XXX: TODO: update DBSR[MRR] */
+ if (level) {
+#if defined(PPC_DEBUG_IRQ)
+ if (loglevel & CPU_LOG_INT) {
+ fprintf(logfile, "%s: reset the PowerPC core\n", __func__);
+ }
+#endif
+ ppc40x_core_reset(env);
+ }
+ break;
+ case PPC405_INPUT_CINT:
+ /* Level sensitive - active high */
+#if defined(PPC_DEBUG_IRQ)
+ if (loglevel & CPU_LOG_INT) {
+ fprintf(logfile, "%s: set the critical IRQ state to %d\n",
+ __func__, level);
+ }
+#endif
+ /* XXX: TOFIX */
+ ppc_set_irq(env, PPC_INTERRUPT_RESET, level);
+ break;
+ case PPC405_INPUT_INT:
+ /* Level sensitive - active high */
+#if defined(PPC_DEBUG_IRQ)
+ if (loglevel & CPU_LOG_INT) {
+ fprintf(logfile, "%s: set the external IRQ state to %d\n",
+ __func__, level);
+ }
+#endif
+ ppc_set_irq(env, PPC_INTERRUPT_EXT, level);
+ break;
+ case PPC405_INPUT_HALT:
+ /* Level sensitive - active low */
+ if (level) {
+#if defined(PPC_DEBUG_IRQ)
+ if (loglevel & CPU_LOG_INT) {
+ fprintf(logfile, "%s: stop the CPU\n", __func__);
+ }
+#endif
+ env->halted = 1;
+ } else {
+#if defined(PPC_DEBUG_IRQ)
+ if (loglevel & CPU_LOG_INT) {
+ fprintf(logfile, "%s: restart the CPU\n", __func__);
+ }
+#endif
+ env->halted = 0;
+ }
+ break;
+ case PPC405_INPUT_DEBUG:
+ /* Level sensitive - active high */
+#if defined(PPC_DEBUG_IRQ)
+ if (loglevel & CPU_LOG_INT) {
+ fprintf(logfile, "%s: set the external IRQ state to %d\n",
+ __func__, level);
+ }
+#endif
+ ppc_set_irq(env, EXCP_40x_DEBUG, level);
+ break;
+ default:
+ /* Unknown pin - do nothing */
+#if defined(PPC_DEBUG_IRQ)
+ if (loglevel & CPU_LOG_INT) {
+ fprintf(logfile, "%s: unknown IRQ pin %d\n", __func__, pin);
+ }
+#endif
+ return;
+ }
+ if (level)
+ env->irq_input_state |= 1 << pin;
+ else
+ env->irq_input_state &= ~(1 << pin);
+ }
+}
+
+void ppc405_irq_init (CPUState *env)
+{
+ env->irq_inputs = (void **)qemu_allocate_irqs(&ppc405_set_irq, env, 7);
+}
+
/*****************************************************************************/
-/* PPC time base and decrementer emulation */
-//#define DEBUG_TB
-
+/* PowerPC time base and decrementer emulation */
struct ppc_tb_t {
/* Time base management */
int64_t tb_offset; /* Compensation */
@@ -35,13 +412,14 @@
/* Decrementer management */
uint64_t decr_next; /* Tick for next decr interrupt */
struct QEMUTimer *decr_timer;
+ void *opaque;
};
static inline uint64_t cpu_ppc_get_tb (ppc_tb_t *tb_env)
{
/* TB time in tb periods */
return muldiv64(qemu_get_clock(vm_clock) + tb_env->tb_offset,
- tb_env->tb_freq, ticks_per_sec);
+ tb_env->tb_freq, ticks_per_sec);
}
uint32_t cpu_ppc_load_tbl (CPUState *env)
@@ -50,16 +428,18 @@
uint64_t tb;
tb = cpu_ppc_get_tb(tb_env);
-#ifdef DEBUG_TB
+#ifdef PPC_DEBUG_TB
{
- static int last_time;
- int now;
- now = time(NULL);
- if (last_time != now) {
- last_time = now;
- printf("%s: tb=0x%016lx %d %08lx\n",
- __func__, tb, now, tb_env->tb_offset);
- }
+ static int last_time;
+ int now;
+ now = time(NULL);
+ if (last_time != now) {
+ last_time = now;
+ if (loglevel != 0) {
+ fprintf(logfile, "%s: tb=0x%016lx %d %08lx\n",
+ __func__, tb, now, tb_env->tb_offset);
+ }
+ }
}
#endif
@@ -72,9 +452,12 @@
uint64_t tb;
tb = cpu_ppc_get_tb(tb_env);
-#ifdef DEBUG_TB
- printf("%s: tb=0x%016lx\n", __func__, tb);
+#if defined(PPC_DEBUG_TB)
+ if (loglevel != 0) {
+ fprintf(logfile, "%s: tb=0x%016lx\n", __func__, tb);
+ }
#endif
+
return tb >> 32;
}
@@ -82,8 +465,11 @@
{
tb_env->tb_offset = muldiv64(value, ticks_per_sec, tb_env->tb_freq)
- qemu_get_clock(vm_clock);
-#ifdef DEBUG_TB
- printf("%s: tb=0x%016lx offset=%08x\n", __func__, value);
+#ifdef PPC_DEBUG_TB
+ if (loglevel != 0) {
+ fprintf(logfile, "%s: tb=0x%016lx offset=%08lx\n", __func__, value,
+ tb_env->tb_offset);
+ }
#endif
}
@@ -114,9 +500,12 @@
decr = muldiv64(diff, tb_env->tb_freq, ticks_per_sec);
else
decr = -muldiv64(-diff, tb_env->tb_freq, ticks_per_sec);
-#if defined(DEBUG_TB)
- printf("%s: 0x%08x\n", __func__, decr);
+#if defined(PPC_DEBUG_TB)
+ if (loglevel != 0) {
+ fprintf(logfile, "%s: 0x%08x\n", __func__, decr);
+ }
#endif
+
return decr;
}
@@ -126,10 +515,12 @@
static inline void cpu_ppc_decr_excp (CPUState *env)
{
/* Raise it */
-#ifdef DEBUG_TB
- printf("raise decrementer exception\n");
+#ifdef PPC_DEBUG_TB
+ if (loglevel != 0) {
+ fprintf(logfile, "raise decrementer exception\n");
+ }
#endif
- cpu_interrupt(env, CPU_INTERRUPT_TIMER);
+ ppc_set_irq(env, PPC_INTERRUPT_DECR, 1);
}
static void _cpu_ppc_store_decr (CPUState *env, uint32_t decr,
@@ -138,15 +529,17 @@
ppc_tb_t *tb_env = env->tb_env;
uint64_t now, next;
-#ifdef DEBUG_TB
- printf("%s: 0x%08x => 0x%08x\n", __func__, decr, value);
+#ifdef PPC_DEBUG_TB
+ if (loglevel != 0) {
+ fprintf(logfile, "%s: 0x%08x => 0x%08x\n", __func__, decr, value);
+ }
#endif
now = qemu_get_clock(vm_clock);
next = now + muldiv64(value, ticks_per_sec, tb_env->tb_freq);
if (is_excp)
next += tb_env->decr_next - now;
if (next == now)
- next++;
+ next++;
tb_env->decr_next = next;
/* Adjust timer */
qemu_mod_timer(tb_env->decr_timer, next);
@@ -154,7 +547,7 @@
* raise an exception.
*/
if ((value & 0x80000000) && !(decr & 0x80000000))
- cpu_ppc_decr_excp(env);
+ cpu_ppc_decr_excp(env);
}
void cpu_ppc_store_decr (CPUState *env, uint32_t value)
@@ -167,8 +560,21 @@
_cpu_ppc_store_decr(opaque, 0x00000000, 0xFFFFFFFF, 1);
}
+static void cpu_ppc_set_tb_clk (void *opaque, uint32_t freq)
+{
+ CPUState *env = opaque;
+ ppc_tb_t *tb_env = env->tb_env;
+
+ tb_env->tb_freq = freq;
+ /* There is a bug in Linux 2.4 kernels:
+ * if a decrementer exception is pending when it enables msr_ee at startup,
+ * it's not ready to handle it...
+ */
+ _cpu_ppc_store_decr(env, 0xFFFFFFFF, 0xFFFFFFFF, 0);
+}
+
/* Set up (once) timebase frequency (in Hz) */
-ppc_tb_t *cpu_ppc_tb_init (CPUState *env, uint32_t freq)
+clk_setup_cb cpu_ppc_tb_init (CPUState *env, uint32_t freq)
{
ppc_tb_t *tb_env;
@@ -176,21 +582,414 @@
if (tb_env == NULL)
return NULL;
env->tb_env = tb_env;
- if (tb_env->tb_freq == 0 || 1) {
- tb_env->tb_freq = freq;
- /* Create new timer */
- tb_env->decr_timer =
- qemu_new_timer(vm_clock, &cpu_ppc_decr_cb, env);
- /* There is a bug in 2.4 kernels:
- * if a decrementer exception is pending when it enables msr_ee,
- * it's not ready to handle it...
- */
- _cpu_ppc_store_decr(env, 0xFFFFFFFF, 0xFFFFFFFF, 0);
+ /* Create new timer */
+ tb_env->decr_timer = qemu_new_timer(vm_clock, &cpu_ppc_decr_cb, env);
+ cpu_ppc_set_tb_clk(env, freq);
+
+ return &cpu_ppc_set_tb_clk;
+}
+
+/* Specific helpers for POWER & PowerPC 601 RTC */
+clk_setup_cb cpu_ppc601_rtc_init (CPUState *env)
+{
+ return cpu_ppc_tb_init(env, 7812500);
+}
+
+void cpu_ppc601_store_rtcu (CPUState *env, uint32_t value)
+__attribute__ (( alias ("cpu_ppc_store_tbu") ));
+
+uint32_t cpu_ppc601_load_rtcu (CPUState *env)
+__attribute__ (( alias ("cpu_ppc_load_tbu") ));
+
+void cpu_ppc601_store_rtcl (CPUState *env, uint32_t value)
+{
+ cpu_ppc_store_tbl(env, value & 0x3FFFFF80);
+}
+
+uint32_t cpu_ppc601_load_rtcl (CPUState *env)
+{
+ return cpu_ppc_load_tbl(env) & 0x3FFFFF80;
+}
+
+/*****************************************************************************/
+/* Embedded PowerPC timers */
+
+/* PIT, FIT & WDT */
+typedef struct ppcemb_timer_t ppcemb_timer_t;
+struct ppcemb_timer_t {
+ uint64_t pit_reload; /* PIT auto-reload value */
+ uint64_t fit_next; /* Tick for next FIT interrupt */
+ struct QEMUTimer *fit_timer;
+ uint64_t wdt_next; /* Tick for next WDT interrupt */
+ struct QEMUTimer *wdt_timer;
+};
+
+/* Fixed interval timer */
+static void cpu_4xx_fit_cb (void *opaque)
+{
+ CPUState *env;
+ ppc_tb_t *tb_env;
+ ppcemb_timer_t *ppcemb_timer;
+ uint64_t now, next;
+
+ env = opaque;
+ tb_env = env->tb_env;
+ ppcemb_timer = tb_env->opaque;
+ now = qemu_get_clock(vm_clock);
+ switch ((env->spr[SPR_40x_TCR] >> 24) & 0x3) {
+ case 0:
+ next = 1 << 9;
+ break;
+ case 1:
+ next = 1 << 13;
+ break;
+ case 2:
+ next = 1 << 17;
+ break;
+ case 3:
+ next = 1 << 21;
+ break;
+ default:
+ /* Cannot occur, but makes gcc happy */
+ return;
}
+ next = now + muldiv64(next, ticks_per_sec, tb_env->tb_freq);
+ if (next == now)
+ next++;
+ qemu_mod_timer(ppcemb_timer->fit_timer, next);
+ env->spr[SPR_40x_TSR] |= 1 << 26;
+ if ((env->spr[SPR_40x_TCR] >> 23) & 0x1)
+ ppc_set_irq(env, PPC_INTERRUPT_FIT, 1);
+#ifdef PPC_DEBUG_TB
+ if (loglevel != 0) {
+ fprintf(logfile, "%s: ir %d TCR " ADDRX " TSR " ADDRX "\n", __func__,
+ (int)((env->spr[SPR_40x_TCR] >> 23) & 0x1),
+ env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]);
+ }
+#endif
+}
- return tb_env;
+/* Programmable interval timer */
+static void start_stop_pit (CPUState *env, ppc_tb_t *tb_env, int is_excp)
+{
+ ppcemb_timer_t *ppcemb_timer;
+ uint64_t now, next;
+
+ ppcemb_timer = tb_env->opaque;
+ if (ppcemb_timer->pit_reload <= 1 ||
+ !((env->spr[SPR_40x_TCR] >> 26) & 0x1) ||
+ (is_excp && !((env->spr[SPR_40x_TCR] >> 22) & 0x1))) {
+ /* Stop PIT */
+#ifdef PPC_DEBUG_TB
+ if (loglevel != 0) {
+ fprintf(logfile, "%s: stop PIT\n", __func__);
+ }
+#endif
+ qemu_del_timer(tb_env->decr_timer);
+ } else {
+#ifdef PPC_DEBUG_TB
+ if (loglevel != 0) {
+ fprintf(logfile, "%s: start PIT 0x" REGX "\n",
+ __func__, ppcemb_timer->pit_reload);
+ }
+#endif
+ now = qemu_get_clock(vm_clock);
+ next = now + muldiv64(ppcemb_timer->pit_reload,
+ ticks_per_sec, tb_env->tb_freq);
+ if (is_excp)
+ next += tb_env->decr_next - now;
+ if (next == now)
+ next++;
+ qemu_mod_timer(tb_env->decr_timer, next);
+ tb_env->decr_next = next;
+ }
}
+static void cpu_4xx_pit_cb (void *opaque)
+{
+ CPUState *env;
+ ppc_tb_t *tb_env;
+ ppcemb_timer_t *ppcemb_timer;
+
+ env = opaque;
+ tb_env = env->tb_env;
+ ppcemb_timer = tb_env->opaque;
+ env->spr[SPR_40x_TSR] |= 1 << 27;
+ if ((env->spr[SPR_40x_TCR] >> 26) & 0x1)
+ ppc_set_irq(env, PPC_INTERRUPT_PIT, 1);
+ start_stop_pit(env, tb_env, 1);
+#ifdef PPC_DEBUG_TB
+ if (loglevel != 0) {
+ fprintf(logfile, "%s: ar %d ir %d TCR " ADDRX " TSR " ADDRX " "
+ "%016" PRIx64 "\n", __func__,
+ (int)((env->spr[SPR_40x_TCR] >> 22) & 0x1),
+ (int)((env->spr[SPR_40x_TCR] >> 26) & 0x1),
+ env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR],
+ ppcemb_timer->pit_reload);
+ }
+#endif
+}
+
+/* Watchdog timer */
+static void cpu_4xx_wdt_cb (void *opaque)
+{
+ CPUState *env;
+ ppc_tb_t *tb_env;
+ ppcemb_timer_t *ppcemb_timer;
+ uint64_t now, next;
+
+ env = opaque;
+ tb_env = env->tb_env;
+ ppcemb_timer = tb_env->opaque;
+ now = qemu_get_clock(vm_clock);
+ switch ((env->spr[SPR_40x_TCR] >> 30) & 0x3) {
+ case 0:
+ next = 1 << 17;
+ break;
+ case 1:
+ next = 1 << 21;
+ break;
+ case 2:
+ next = 1 << 25;
+ break;
+ case 3:
+ next = 1 << 29;
+ break;
+ default:
+ /* Cannot occur, but makes gcc happy */
+ return;
+ }
+ next = now + muldiv64(next, ticks_per_sec, tb_env->tb_freq);
+ if (next == now)
+ next++;
+#ifdef PPC_DEBUG_TB
+ if (loglevel != 0) {
+ fprintf(logfile, "%s: TCR " ADDRX " TSR " ADDRX "\n", __func__,
+ env->spr[SPR_40x_TCR], env->spr[SPR_40x_TSR]);
+ }
+#endif
+ switch ((env->spr[SPR_40x_TSR] >> 30) & 0x3) {
+ case 0x0:
+ case 0x1:
+ qemu_mod_timer(ppcemb_timer->wdt_timer, next);
+ ppcemb_timer->wdt_next = next;
+ env->spr[SPR_40x_TSR] |= 1 << 31;
+ break;
+ case 0x2:
+ qemu_mod_timer(ppcemb_timer->wdt_timer, next);
+ ppcemb_timer->wdt_next = next;
+ env->spr[SPR_40x_TSR] |= 1 << 30;
+ if ((env->spr[SPR_40x_TCR] >> 27) & 0x1)
+ ppc_set_irq(env, PPC_INTERRUPT_WDT, 1);
+ break;
+ case 0x3:
+ env->spr[SPR_40x_TSR] &= ~0x30000000;
+ env->spr[SPR_40x_TSR] |= env->spr[SPR_40x_TCR] & 0x30000000;
+ switch ((env->spr[SPR_40x_TCR] >> 28) & 0x3) {
+ case 0x0:
+ /* No reset */
+ break;
+ case 0x1: /* Core reset */
+ ppc40x_core_reset(env);
+ break;
+ case 0x2: /* Chip reset */
+ ppc40x_chip_reset(env);
+ break;
+ case 0x3: /* System reset */
+ ppc40x_system_reset(env);
+ break;
+ }
+ }
+}
+
+void store_40x_pit (CPUState *env, target_ulong val)
+{
+ ppc_tb_t *tb_env;
+ ppcemb_timer_t *ppcemb_timer;
+
+ tb_env = env->tb_env;
+ ppcemb_timer = tb_env->opaque;
+#ifdef PPC_DEBUG_TB
+ if (loglevel != 0) {
+ fprintf(logfile, "%s %p %p\n", __func__, tb_env, ppcemb_timer);
+ }
+#endif
+ ppcemb_timer->pit_reload = val;
+ start_stop_pit(env, tb_env, 0);
+}
+
+target_ulong load_40x_pit (CPUState *env)
+{
+ return cpu_ppc_load_decr(env);
+}
+
+void store_booke_tsr (CPUState *env, target_ulong val)
+{
+#ifdef PPC_DEBUG_TB
+ if (loglevel != 0) {
+ fprintf(logfile, "%s: val=" ADDRX "\n", __func__, val);
+ }
+#endif
+ env->spr[SPR_40x_TSR] &= ~(val & 0xFC000000);
+ if (val & 0x80000000)
+ ppc_set_irq(env, PPC_INTERRUPT_PIT, 0);
+}
+
+void store_booke_tcr (CPUState *env, target_ulong val)
+{
+ ppc_tb_t *tb_env;
+
+ tb_env = env->tb_env;
+#ifdef PPC_DEBUG_TB
+ if (loglevel != 0) {
+ fprintf(logfile, "%s: val=" ADDRX "\n", __func__, val);
+ }
+#endif
+ env->spr[SPR_40x_TCR] = val & 0xFFC00000;
+ start_stop_pit(env, tb_env, 1);
+ cpu_4xx_wdt_cb(env);
+}
+
+static void ppc_emb_set_tb_clk (void *opaque, uint32_t freq)
+{
+ CPUState *env = opaque;
+ ppc_tb_t *tb_env = env->tb_env;
+
+#ifdef PPC_DEBUG_TB
+ if (loglevel != 0) {
+ fprintf(logfile, "%s set new frequency to %u\n", __func__, freq);
+ }
+#endif
+ tb_env->tb_freq = freq;
+ /* XXX: we should also update all timers */
+}
+
+clk_setup_cb ppc_emb_timers_init (CPUState *env, uint32_t freq)
+{
+ ppc_tb_t *tb_env;
+ ppcemb_timer_t *ppcemb_timer;
+
+ tb_env = qemu_mallocz(sizeof(ppc_tb_t));
+ if (tb_env == NULL) {
+ return NULL;
+ }
+ env->tb_env = tb_env;
+ ppcemb_timer = qemu_mallocz(sizeof(ppcemb_timer_t));
+ tb_env->tb_freq = freq;
+ tb_env->opaque = ppcemb_timer;
+#ifdef PPC_DEBUG_TB
+ if (loglevel != 0) {
+ fprintf(logfile, "%s %p %p %p\n", __func__, tb_env, ppcemb_timer,
+ &ppc_emb_set_tb_clk);
+ }
+#endif
+ if (ppcemb_timer != NULL) {
+ /* We use decr timer for PIT */
+ tb_env->decr_timer = qemu_new_timer(vm_clock, &cpu_4xx_pit_cb, env);
+ ppcemb_timer->fit_timer =
+ qemu_new_timer(vm_clock, &cpu_4xx_fit_cb, env);
+ ppcemb_timer->wdt_timer =
+ qemu_new_timer(vm_clock, &cpu_4xx_wdt_cb, env);
+ }
+
+ return &ppc_emb_set_tb_clk;
+}
+
+/*****************************************************************************/
+/* Embedded PowerPC Device Control Registers */
+typedef struct ppc_dcrn_t ppc_dcrn_t;
+struct ppc_dcrn_t {
+ dcr_read_cb dcr_read;
+ dcr_write_cb dcr_write;
+ void *opaque;
+};
+
+#define DCRN_NB 1024
+struct ppc_dcr_t {
+ ppc_dcrn_t dcrn[DCRN_NB];
+ int (*read_error)(int dcrn);
+ int (*write_error)(int dcrn);
+};
+
+int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, target_ulong *valp)
+{
+ ppc_dcrn_t *dcr;
+
+ if (dcrn < 0 || dcrn >= DCRN_NB)
+ goto error;
+ dcr = &dcr_env->dcrn[dcrn];
+ if (dcr->dcr_read == NULL)
+ goto error;
+ *valp = (*dcr->dcr_read)(dcr->opaque, dcrn);
+
+ return 0;
+
+ error:
+ if (dcr_env->read_error != NULL)
+ return (*dcr_env->read_error)(dcrn);
+
+ return -1;
+}
+
+int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, target_ulong val)
+{
+ ppc_dcrn_t *dcr;
+
+ if (dcrn < 0 || dcrn >= DCRN_NB)
+ goto error;
+ dcr = &dcr_env->dcrn[dcrn];
+ if (dcr->dcr_write == NULL)
+ goto error;
+ (*dcr->dcr_write)(dcr->opaque, dcrn, val);
+
+ return 0;
+
+ error:
+ if (dcr_env->write_error != NULL)
+ return (*dcr_env->write_error)(dcrn);
+
+ return -1;
+}
+
+int ppc_dcr_register (CPUState *env, int dcrn, void *opaque,
+ dcr_read_cb dcr_read, dcr_write_cb dcr_write)
+{
+ ppc_dcr_t *dcr_env;
+ ppc_dcrn_t *dcr;
+
+ dcr_env = env->dcr_env;
+ if (dcr_env == NULL)
+ return -1;
+ if (dcrn < 0 || dcrn >= DCRN_NB)
+ return -1;
+ dcr = &dcr_env->dcrn[dcrn];
+ if (dcr->opaque != NULL ||
+ dcr->dcr_read != NULL ||
+ dcr->dcr_write != NULL)
+ return -1;
+ dcr->opaque = opaque;
+ dcr->dcr_read = dcr_read;
+ dcr->dcr_write = dcr_write;
+
+ return 0;
+}
+
+int ppc_dcr_init (CPUState *env, int (*read_error)(int dcrn),
+ int (*write_error)(int dcrn))
+{
+ ppc_dcr_t *dcr_env;
+
+ dcr_env = qemu_mallocz(sizeof(ppc_dcr_t));
+ if (dcr_env == NULL)
+ return -1;
+ dcr_env->read_error = read_error;
+ dcr_env->write_error = write_error;
+ env->dcr_env = dcr_env;
+
+ return 0;
+}
+
+
#if 0
/*****************************************************************************/
/* Handle system reset (for now, just stop emulation) */
@@ -264,6 +1063,7 @@
tmp |= m48t59_read(nvram, addr + 1) << 16;
tmp |= m48t59_read(nvram, addr + 2) << 8;
tmp |= m48t59_read(nvram, addr + 3);
+
return tmp;
}
@@ -316,10 +1116,10 @@
odd = count & 1;
count &= ~1;
for (i = 0; i != count; i++) {
- crc = NVRAM_crc_update(crc, NVRAM_get_word(nvram, start + i));
+ crc = NVRAM_crc_update(crc, NVRAM_get_word(nvram, start + i));
}
if (odd) {
- crc = NVRAM_crc_update(crc, NVRAM_get_byte(nvram, start + i) << 8);
+ crc = NVRAM_crc_update(crc, NVRAM_get_byte(nvram, start + i) << 8);
}
return crc;
Added: trunk/src/host/qemu-neo1973/hw/ppc405.h
===================================================================
--- trunk/src/host/qemu-neo1973/hw/ppc405.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/ppc405.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,122 @@
+/*
+ * QEMU PowerPC 405 shared definitions
+ *
+ * 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.
+ */
+
+#if !defined(PPC_405_H)
+#define PPC_405_H
+
+/* Bootinfo as set-up by u-boot */
+typedef struct ppc4xx_bd_info_t ppc4xx_bd_info_t;
+struct ppc4xx_bd_info_t {
+ uint32_t bi_memstart;
+ uint32_t bi_memsize;
+ uint32_t bi_flashstart;
+ uint32_t bi_flashsize;
+ uint32_t bi_flashoffset; /* 0x10 */
+ uint32_t bi_sramstart;
+ uint32_t bi_sramsize;
+ uint32_t bi_bootflags;
+ uint32_t bi_ipaddr; /* 0x20 */
+ uint8_t bi_enetaddr[6];
+ uint16_t bi_ethspeed;
+ uint32_t bi_intfreq;
+ uint32_t bi_busfreq; /* 0x30 */
+ uint32_t bi_baudrate;
+ uint8_t bi_s_version[4];
+ uint8_t bi_r_version[32];
+ uint32_t bi_procfreq;
+ uint32_t bi_plb_busfreq;
+ uint32_t bi_pci_busfreq;
+ uint8_t bi_pci_enetaddr[6];
+ uint32_t bi_pci_enetaddr2[6];
+ uint32_t bi_opbfreq;
+ uint32_t bi_iic_fast[2];
+};
+
+/* PowerPC 405 core */
+CPUState *ppc405_init (const unsigned char *cpu_model,
+ clk_setup_t *cpu_clk, clk_setup_t *tb_clk,
+ uint32_t sysclk);
+ram_addr_t ppc405_set_bootinfo (CPUState *env, ppc4xx_bd_info_t *bd);
+
+/* */
+typedef struct ppc4xx_mmio_t ppc4xx_mmio_t;
+int ppc4xx_mmio_register (CPUState *env, ppc4xx_mmio_t *mmio,
+ target_phys_addr_t offset, uint32_t len,
+ CPUReadMemoryFunc **mem_read,
+ CPUWriteMemoryFunc **mem_write, void *opaque);
+ppc4xx_mmio_t *ppc4xx_mmio_init (CPUState *env, target_phys_addr_t base);
+/* PowerPC 4xx peripheral local bus arbitrer */
+void ppc4xx_plb_init (CPUState *env);
+/* PLB to OPB bridge */
+void ppc4xx_pob_init (CPUState *env);
+/* OPB arbitrer */
+void ppc4xx_opba_init (CPUState *env, ppc4xx_mmio_t *mmio,
+ target_phys_addr_t offset);
+/* PowerPC 4xx universal interrupt controller */
+enum {
+ PPCUIC_OUTPUT_INT = 0,
+ PPCUIC_OUTPUT_CINT = 1,
+ PPCUIC_OUTPUT_NB,
+};
+qemu_irq *ppcuic_init (CPUState *env, qemu_irq *irqs,
+ uint32_t dcr_base, int has_ssr, int has_vr);
+/* SDRAM controller */
+void ppc405_sdram_init (CPUState *env, qemu_irq irq, int nbanks,
+ target_ulong *ram_bases, target_ulong *ram_sizes,
+ int do_init);
+/* Peripheral controller */
+void ppc405_ebc_init (CPUState *env);
+/* DMA controller */
+void ppc405_dma_init (CPUState *env, qemu_irq irqs[4]);
+/* GPIO */
+void ppc405_gpio_init (CPUState *env, ppc4xx_mmio_t *mmio,
+ target_phys_addr_t offset);
+/* Serial ports */
+void ppc405_serial_init (CPUState *env, ppc4xx_mmio_t *mmio,
+ target_phys_addr_t offset, qemu_irq irq,
+ CharDriverState *chr);
+/* On Chip Memory */
+void ppc405_ocm_init (CPUState *env, unsigned long offset);
+/* I2C controller */
+void ppc405_i2c_init (CPUState *env, ppc4xx_mmio_t *mmio,
+ target_phys_addr_t offset, qemu_irq irq);
+/* General purpose timers */
+void ppc4xx_gpt_init (CPUState *env, ppc4xx_mmio_t *mmio,
+ target_phys_addr_t offset, qemu_irq irq[5]);
+/* Memory access layer */
+void ppc405_mal_init (CPUState *env, qemu_irq irqs[4]);
+/* PowerPC 405 microcontrollers */
+CPUState *ppc405cr_init (target_ulong ram_bases[4], target_ulong ram_sizes[4],
+ uint32_t sysclk, qemu_irq **picp,
+ ram_addr_t *offsetp, int do_init);
+CPUState *ppc405ep_init (target_ulong ram_bases[2], target_ulong ram_sizes[2],
+ uint32_t sysclk, qemu_irq **picp,
+ ram_addr_t *offsetp, int do_init);
+/* IBM STBxxx microcontrollers */
+CPUState *ppc_stb025_init (target_ulong ram_bases[2],
+ target_ulong ram_sizes[2],
+ uint32_t sysclk, qemu_irq **picp,
+ ram_addr_t *offsetp);
+
+#endif /* !defined(PPC_405_H) */
Added: trunk/src/host/qemu-neo1973/hw/ppc405_boards.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/ppc405_boards.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/ppc405_boards.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,630 @@
+/*
+ * QEMU PowerPC 405 evaluation boards emulation
+ *
+ * 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 "vl.h"
+#include "ppc405.h"
+
+extern int loglevel;
+extern FILE *logfile;
+
+#define BIOS_FILENAME "ppc405_rom.bin"
+#undef BIOS_SIZE
+#define BIOS_SIZE (2048 * 1024)
+
+#define KERNEL_LOAD_ADDR 0x00000000
+#define INITRD_LOAD_ADDR 0x01800000
+
+#define USE_FLASH_BIOS
+
+#define DEBUG_BOARD_INIT
+
+/*****************************************************************************/
+/* PPC405EP reference board (IBM) */
+/* Standalone board with:
+ * - PowerPC 405EP CPU
+ * - SDRAM (0x00000000)
+ * - Flash (0xFFF80000)
+ * - SRAM (0xFFF00000)
+ * - NVRAM (0xF0000000)
+ * - FPGA (0xF0300000)
+ */
+typedef struct ref405ep_fpga_t ref405ep_fpga_t;
+struct ref405ep_fpga_t {
+ uint32_t base;
+ uint8_t reg0;
+ uint8_t reg1;
+};
+
+static uint32_t ref405ep_fpga_readb (void *opaque, target_phys_addr_t addr)
+{
+ ref405ep_fpga_t *fpga;
+ uint32_t ret;
+
+ fpga = opaque;
+ addr -= fpga->base;
+ switch (addr) {
+ case 0x0:
+ ret = fpga->reg0;
+ break;
+ case 0x1:
+ ret = fpga->reg1;
+ break;
+ default:
+ ret = 0;
+ break;
+ }
+
+ return ret;
+}
+
+static void ref405ep_fpga_writeb (void *opaque,
+ target_phys_addr_t addr, uint32_t value)
+{
+ ref405ep_fpga_t *fpga;
+
+ fpga = opaque;
+ addr -= fpga->base;
+ switch (addr) {
+ case 0x0:
+ /* Read only */
+ break;
+ case 0x1:
+ fpga->reg1 = value;
+ break;
+ default:
+ break;
+ }
+}
+
+static uint32_t ref405ep_fpga_readw (void *opaque, target_phys_addr_t addr)
+{
+ uint32_t ret;
+
+ ret = ref405ep_fpga_readb(opaque, addr) << 8;
+ ret |= ref405ep_fpga_readb(opaque, addr + 1);
+
+ return ret;
+}
+
+static void ref405ep_fpga_writew (void *opaque,
+ target_phys_addr_t addr, uint32_t value)
+{
+ ref405ep_fpga_writeb(opaque, addr, (value >> 8) & 0xFF);
+ ref405ep_fpga_writeb(opaque, addr + 1, value & 0xFF);
+}
+
+static uint32_t ref405ep_fpga_readl (void *opaque, target_phys_addr_t addr)
+{
+ uint32_t ret;
+
+ ret = ref405ep_fpga_readb(opaque, addr) << 24;
+ ret |= ref405ep_fpga_readb(opaque, addr + 1) << 16;
+ ret |= ref405ep_fpga_readb(opaque, addr + 2) << 8;
+ ret |= ref405ep_fpga_readb(opaque, addr + 3);
+
+ return ret;
+}
+
+static void ref405ep_fpga_writel (void *opaque,
+ target_phys_addr_t addr, uint32_t value)
+{
+ ref405ep_fpga_writel(opaque, addr, (value >> 24) & 0xFF);
+ ref405ep_fpga_writel(opaque, addr + 1, (value >> 16) & 0xFF);
+ ref405ep_fpga_writel(opaque, addr + 2, (value >> 8) & 0xFF);
+ ref405ep_fpga_writeb(opaque, addr + 3, value & 0xFF);
+}
+
+static CPUReadMemoryFunc *ref405ep_fpga_read[] = {
+ &ref405ep_fpga_readb,
+ &ref405ep_fpga_readw,
+ &ref405ep_fpga_readl,
+};
+
+static CPUWriteMemoryFunc *ref405ep_fpga_write[] = {
+ &ref405ep_fpga_writeb,
+ &ref405ep_fpga_writew,
+ &ref405ep_fpga_writel,
+};
+
+static void ref405ep_fpga_reset (void *opaque)
+{
+ ref405ep_fpga_t *fpga;
+
+ fpga = opaque;
+ fpga->reg0 = 0x00;
+ fpga->reg1 = 0x0F;
+}
+
+static void ref405ep_fpga_init (uint32_t base)
+{
+ ref405ep_fpga_t *fpga;
+ int fpga_memory;
+
+ fpga = qemu_mallocz(sizeof(ref405ep_fpga_t));
+ if (fpga != NULL) {
+ fpga->base = base;
+ fpga_memory = cpu_register_io_memory(0, ref405ep_fpga_read,
+ ref405ep_fpga_write, fpga);
+ cpu_register_physical_memory(base, 0x00000100, fpga_memory);
+ ref405ep_fpga_reset(fpga);
+ qemu_register_reset(&ref405ep_fpga_reset, fpga);
+ }
+}
+
+static void ref405ep_init (int ram_size, int vga_ram_size, int boot_device,
+ DisplayState *ds, const char **fd_filename,
+ int snapshot,
+ const char *kernel_filename,
+ const char *kernel_cmdline,
+ const char *initrd_filename,
+ const char *cpu_model)
+{
+ char buf[1024];
+ ppc4xx_bd_info_t bd;
+ CPUPPCState *env;
+ qemu_irq *pic;
+ ram_addr_t sram_offset, bios_offset, bdloc;
+ target_ulong ram_bases[2], ram_sizes[2];
+ target_ulong sram_size, bios_size;
+ //int phy_addr = 0;
+ //static int phy_addr = 1;
+ target_ulong kernel_base, kernel_size, initrd_base, initrd_size;
+ int linux_boot;
+ int fl_idx, fl_sectors, len;
+
+ /* XXX: fix this */
+ ram_bases[0] = 0x00000000;
+ ram_sizes[0] = 0x08000000;
+ ram_bases[1] = 0x00000000;
+ ram_sizes[1] = 0x00000000;
+ ram_size = 128 * 1024 * 1024;
+#ifdef DEBUG_BOARD_INIT
+ printf("%s: register cpu\n", __func__);
+#endif
+ env = ppc405ep_init(ram_bases, ram_sizes, 33333333, &pic, &sram_offset,
+ kernel_filename == NULL ? 0 : 1);
+ /* allocate SRAM */
+#ifdef DEBUG_BOARD_INIT
+ printf("%s: register SRAM at offset %08lx\n", __func__, sram_offset);
+#endif
+ sram_size = 512 * 1024;
+ cpu_register_physical_memory(0xFFF00000, sram_size,
+ sram_offset | IO_MEM_RAM);
+ /* allocate and load BIOS */
+#ifdef DEBUG_BOARD_INIT
+ printf("%s: register BIOS\n", __func__);
+#endif
+ bios_offset = sram_offset + sram_size;
+ fl_idx = 0;
+#ifdef USE_FLASH_BIOS
+ if (pflash_table[fl_idx] != NULL) {
+ bios_size = bdrv_getlength(pflash_table[fl_idx]);
+ fl_sectors = (bios_size + 65535) >> 16;
+#ifdef DEBUG_BOARD_INIT
+ printf("Register parallel flash %d size " ADDRX " at offset %08lx "
+ " addr " ADDRX " '%s' %d\n",
+ fl_idx, bios_size, bios_offset, -bios_size,
+ bdrv_get_device_name(pflash_table[fl_idx]), fl_sectors);
+#endif
+ pflash_register(-(bios_size), bios_offset, pflash_table[fl_idx],
+ 65536, fl_sectors, 2,
+ 0x0001, 0x22DA, 0x0000, 0x0000);
+ fl_idx++;
+ } else
+#endif
+ {
+#ifdef DEBUG_BOARD_INIT
+ printf("Load BIOS from file\n");
+#endif
+ snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME);
+ bios_size = load_image(buf, phys_ram_base + bios_offset);
+ if (bios_size < 0 || bios_size > BIOS_SIZE) {
+ fprintf(stderr, "qemu: could not load PowerPC bios '%s'\n", buf);
+ exit(1);
+ }
+ bios_size = (bios_size + 0xfff) & ~0xfff;
+ cpu_register_physical_memory((uint32_t)(-bios_size),
+ bios_size, bios_offset | IO_MEM_ROM);
+ }
+ bios_offset += bios_size;
+ /* Register FPGA */
+#ifdef DEBUG_BOARD_INIT
+ printf("%s: register FPGA\n", __func__);
+#endif
+ ref405ep_fpga_init(0xF0300000);
+ /* Register NVRAM */
+#ifdef DEBUG_BOARD_INIT
+ printf("%s: register NVRAM\n", __func__);
+#endif
+ m48t59_init(NULL, 0xF0000000, 0, 8192, 8);
+ /* Load kernel */
+ linux_boot = (kernel_filename != NULL);
+ if (linux_boot) {
+#ifdef DEBUG_BOARD_INIT
+ printf("%s: load kernel\n", __func__);
+#endif
+ memset(&bd, 0, sizeof(bd));
+ bd.bi_memstart = 0x00000000;
+ bd.bi_memsize = ram_size;
+ bd.bi_flashstart = -(bios_size);
+ bd.bi_flashsize = -bios_size;
+ bd.bi_flashoffset = 0;
+ bd.bi_sramstart = 0xFFF00000;
+ bd.bi_sramsize = sram_size;
+ bd.bi_bootflags = 0;
+ bd.bi_intfreq = 133333333;
+ bd.bi_busfreq = 33333333;
+ bd.bi_baudrate = 115200;
+ bd.bi_s_version[0] = 'Q';
+ bd.bi_s_version[1] = 'M';
+ bd.bi_s_version[2] = 'U';
+ bd.bi_s_version[3] = '\0';
+ bd.bi_r_version[0] = 'Q';
+ bd.bi_r_version[1] = 'E';
+ bd.bi_r_version[2] = 'M';
+ bd.bi_r_version[3] = 'U';
+ bd.bi_r_version[4] = '\0';
+ bd.bi_procfreq = 133333333;
+ bd.bi_plb_busfreq = 33333333;
+ bd.bi_pci_busfreq = 33333333;
+ bd.bi_opbfreq = 33333333;
+ bdloc = ppc405_set_bootinfo(env, &bd);
+ env->gpr[3] = bdloc;
+ kernel_base = KERNEL_LOAD_ADDR;
+ /* now we can load the kernel */
+ kernel_size = load_image(kernel_filename, phys_ram_base + kernel_base);
+ if (kernel_size < 0) {
+ fprintf(stderr, "qemu: could not load kernel '%s'\n",
+ kernel_filename);
+ exit(1);
+ }
+ printf("Load kernel size " TARGET_FMT_ld " at " TARGET_FMT_lx
+ " %02x %02x %02x %02x\n", kernel_size, kernel_base,
+ *(char *)(phys_ram_base + kernel_base),
+ *(char *)(phys_ram_base + kernel_base + 1),
+ *(char *)(phys_ram_base + kernel_base + 2),
+ *(char *)(phys_ram_base + kernel_base + 3));
+ /* load initrd */
+ if (initrd_filename) {
+ initrd_base = INITRD_LOAD_ADDR;
+ initrd_size = load_image(initrd_filename,
+ phys_ram_base + initrd_base);
+ if (initrd_size < 0) {
+ fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
+ initrd_filename);
+ exit(1);
+ }
+ } else {
+ initrd_base = 0;
+ initrd_size = 0;
+ }
+ env->gpr[4] = initrd_base;
+ env->gpr[5] = initrd_size;
+ boot_device = 'm';
+ if (kernel_cmdline != NULL) {
+ len = strlen(kernel_cmdline);
+ bdloc -= ((len + 255) & ~255);
+ memcpy(phys_ram_base + bdloc, kernel_cmdline, len + 1);
+ env->gpr[6] = bdloc;
+ env->gpr[7] = bdloc + len;
+ } else {
+ env->gpr[6] = 0;
+ env->gpr[7] = 0;
+ }
+ env->nip = KERNEL_LOAD_ADDR;
+ } else {
+ kernel_base = 0;
+ kernel_size = 0;
+ initrd_base = 0;
+ initrd_size = 0;
+ bdloc = 0;
+ }
+#ifdef DEBUG_BOARD_INIT
+ printf("%s: Done\n", __func__);
+#endif
+ printf("bdloc %016lx %s\n",
+ (unsigned long)bdloc, (char *)(phys_ram_base + bdloc));
+}
+
+QEMUMachine ref405ep_machine = {
+ "ref405ep",
+ "ref405ep",
+ ref405ep_init,
+};
+
+/*****************************************************************************/
+/* AMCC Taihu evaluation board */
+/* - PowerPC 405EP processor
+ * - SDRAM 128 MB at 0x00000000
+ * - Boot flash 2 MB at 0xFFE00000
+ * - Application flash 32 MB at 0xFC000000
+ * - 2 serial ports
+ * - 2 ethernet PHY
+ * - 1 USB 1.1 device 0x50000000
+ * - 1 LCD display 0x50100000
+ * - 1 CPLD 0x50100000
+ * - 1 I2C EEPROM
+ * - 1 I2C thermal sensor
+ * - a set of LEDs
+ * - bit-bang SPI port using GPIOs
+ * - 1 EBC interface connector 0 0x50200000
+ * - 1 cardbus controller + expansion slot.
+ * - 1 PCI expansion slot.
+ */
+typedef struct taihu_cpld_t taihu_cpld_t;
+struct taihu_cpld_t {
+ uint32_t base;
+ uint8_t reg0;
+ uint8_t reg1;
+};
+
+static uint32_t taihu_cpld_readb (void *opaque, target_phys_addr_t addr)
+{
+ taihu_cpld_t *cpld;
+ uint32_t ret;
+
+ cpld = opaque;
+ addr -= cpld->base;
+ switch (addr) {
+ case 0x0:
+ ret = cpld->reg0;
+ break;
+ case 0x1:
+ ret = cpld->reg1;
+ break;
+ default:
+ ret = 0;
+ break;
+ }
+
+ return ret;
+}
+
+static void taihu_cpld_writeb (void *opaque,
+ target_phys_addr_t addr, uint32_t value)
+{
+ taihu_cpld_t *cpld;
+
+ cpld = opaque;
+ addr -= cpld->base;
+ switch (addr) {
+ case 0x0:
+ /* Read only */
+ break;
+ case 0x1:
+ cpld->reg1 = value;
+ break;
+ default:
+ break;
+ }
+}
+
+static uint32_t taihu_cpld_readw (void *opaque, target_phys_addr_t addr)
+{
+ uint32_t ret;
+
+ ret = taihu_cpld_readb(opaque, addr) << 8;
+ ret |= taihu_cpld_readb(opaque, addr + 1);
+
+ return ret;
+}
+
+static void taihu_cpld_writew (void *opaque,
+ target_phys_addr_t addr, uint32_t value)
+{
+ taihu_cpld_writeb(opaque, addr, (value >> 8) & 0xFF);
+ taihu_cpld_writeb(opaque, addr + 1, value & 0xFF);
+}
+
+static uint32_t taihu_cpld_readl (void *opaque, target_phys_addr_t addr)
+{
+ uint32_t ret;
+
+ ret = taihu_cpld_readb(opaque, addr) << 24;
+ ret |= taihu_cpld_readb(opaque, addr + 1) << 16;
+ ret |= taihu_cpld_readb(opaque, addr + 2) << 8;
+ ret |= taihu_cpld_readb(opaque, addr + 3);
+
+ return ret;
+}
+
+static void taihu_cpld_writel (void *opaque,
+ target_phys_addr_t addr, uint32_t value)
+{
+ taihu_cpld_writel(opaque, addr, (value >> 24) & 0xFF);
+ taihu_cpld_writel(opaque, addr + 1, (value >> 16) & 0xFF);
+ taihu_cpld_writel(opaque, addr + 2, (value >> 8) & 0xFF);
+ taihu_cpld_writeb(opaque, addr + 3, value & 0xFF);
+}
+
+static CPUReadMemoryFunc *taihu_cpld_read[] = {
+ &taihu_cpld_readb,
+ &taihu_cpld_readw,
+ &taihu_cpld_readl,
+};
+
+static CPUWriteMemoryFunc *taihu_cpld_write[] = {
+ &taihu_cpld_writeb,
+ &taihu_cpld_writew,
+ &taihu_cpld_writel,
+};
+
+static void taihu_cpld_reset (void *opaque)
+{
+ taihu_cpld_t *cpld;
+
+ cpld = opaque;
+ cpld->reg0 = 0x01;
+ cpld->reg1 = 0x80;
+}
+
+static void taihu_cpld_init (uint32_t base)
+{
+ taihu_cpld_t *cpld;
+ int cpld_memory;
+
+ cpld = qemu_mallocz(sizeof(taihu_cpld_t));
+ if (cpld != NULL) {
+ cpld->base = base;
+ cpld_memory = cpu_register_io_memory(0, taihu_cpld_read,
+ taihu_cpld_write, cpld);
+ cpu_register_physical_memory(base, 0x00000100, cpld_memory);
+ taihu_cpld_reset(cpld);
+ qemu_register_reset(&taihu_cpld_reset, cpld);
+ }
+}
+
+static void taihu_405ep_init(int ram_size, int vga_ram_size, int boot_device,
+ DisplayState *ds, const char **fd_filename,
+ int snapshot,
+ const char *kernel_filename,
+ const char *kernel_cmdline,
+ const char *initrd_filename,
+ const char *cpu_model)
+{
+ char buf[1024];
+ CPUPPCState *env;
+ qemu_irq *pic;
+ ram_addr_t bios_offset;
+ target_ulong ram_bases[2], ram_sizes[2];
+ target_ulong bios_size;
+ target_ulong kernel_base, kernel_size, initrd_base, initrd_size;
+ int linux_boot;
+ int fl_idx, fl_sectors;
+
+ /* RAM is soldered to the board so the size cannot be changed */
+ ram_bases[0] = 0x00000000;
+ ram_sizes[0] = 0x04000000;
+ ram_bases[1] = 0x04000000;
+ ram_sizes[1] = 0x04000000;
+#ifdef DEBUG_BOARD_INIT
+ printf("%s: register cpu\n", __func__);
+#endif
+ env = ppc405ep_init(ram_bases, ram_sizes, 33333333, &pic, &bios_offset,
+ kernel_filename == NULL ? 0 : 1);
+ /* allocate and load BIOS */
+#ifdef DEBUG_BOARD_INIT
+ printf("%s: register BIOS\n", __func__);
+#endif
+ fl_idx = 0;
+#if defined(USE_FLASH_BIOS)
+ if (pflash_table[fl_idx] != NULL) {
+ bios_size = bdrv_getlength(pflash_table[fl_idx]);
+ /* XXX: should check that size is 2MB */
+ // bios_size = 2 * 1024 * 1024;
+ fl_sectors = (bios_size + 65535) >> 16;
+#ifdef DEBUG_BOARD_INIT
+ printf("Register parallel flash %d size " ADDRX " at offset %08lx "
+ " addr " ADDRX " '%s' %d\n",
+ fl_idx, bios_size, bios_offset, -bios_size,
+ bdrv_get_device_name(pflash_table[fl_idx]), fl_sectors);
+#endif
+ pflash_register(-(bios_size), bios_offset, pflash_table[fl_idx],
+ 65536, fl_sectors, 4,
+ 0x0001, 0x22DA, 0x0000, 0x0000);
+ fl_idx++;
+ } else
+#endif
+ {
+#ifdef DEBUG_BOARD_INIT
+ printf("Load BIOS from file\n");
+#endif
+ snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME);
+ bios_size = load_image(buf, phys_ram_base + bios_offset);
+ if (bios_size < 0 || bios_size > BIOS_SIZE) {
+ fprintf(stderr, "qemu: could not load PowerPC bios '%s'\n", buf);
+ exit(1);
+ }
+ bios_size = (bios_size + 0xfff) & ~0xfff;
+ cpu_register_physical_memory((uint32_t)(-bios_size),
+ bios_size, bios_offset | IO_MEM_ROM);
+ }
+ bios_offset += bios_size;
+ /* Register Linux flash */
+ if (pflash_table[fl_idx] != NULL) {
+ bios_size = bdrv_getlength(pflash_table[fl_idx]);
+ /* XXX: should check that size is 32MB */
+ bios_size = 32 * 1024 * 1024;
+ fl_sectors = (bios_size + 65535) >> 16;
+#ifdef DEBUG_BOARD_INIT
+ printf("Register parallel flash %d size " ADDRX " at offset %08lx "
+ " addr " ADDRX " '%s'\n",
+ fl_idx, bios_size, bios_offset, (target_ulong)0xfc000000,
+ bdrv_get_device_name(pflash_table[fl_idx]));
+#endif
+ pflash_register(0xfc000000, bios_offset, pflash_table[fl_idx],
+ 65536, fl_sectors, 4,
+ 0x0001, 0x22DA, 0x0000, 0x0000);
+ fl_idx++;
+ }
+ /* Register CLPD & LCD display */
+#ifdef DEBUG_BOARD_INIT
+ printf("%s: register CPLD\n", __func__);
+#endif
+ taihu_cpld_init(0x50100000);
+ /* Load kernel */
+ linux_boot = (kernel_filename != NULL);
+ if (linux_boot) {
+#ifdef DEBUG_BOARD_INIT
+ printf("%s: load kernel\n", __func__);
+#endif
+ kernel_base = KERNEL_LOAD_ADDR;
+ /* now we can load the kernel */
+ kernel_size = load_image(kernel_filename, phys_ram_base + kernel_base);
+ if (kernel_size < 0) {
+ fprintf(stderr, "qemu: could not load kernel '%s'\n",
+ kernel_filename);
+ exit(1);
+ }
+ /* load initrd */
+ if (initrd_filename) {
+ initrd_base = INITRD_LOAD_ADDR;
+ initrd_size = load_image(initrd_filename,
+ phys_ram_base + initrd_base);
+ if (initrd_size < 0) {
+ fprintf(stderr,
+ "qemu: could not load initial ram disk '%s'\n",
+ initrd_filename);
+ exit(1);
+ }
+ } else {
+ initrd_base = 0;
+ initrd_size = 0;
+ }
+ boot_device = 'm';
+ } else {
+ kernel_base = 0;
+ kernel_size = 0;
+ initrd_base = 0;
+ initrd_size = 0;
+ }
+#ifdef DEBUG_BOARD_INIT
+ printf("%s: Done\n", __func__);
+#endif
+}
+
+QEMUMachine taihu_machine = {
+ "taihu",
+ "taihu",
+ taihu_405ep_init,
+};
Added: trunk/src/host/qemu-neo1973/hw/ppc405_uc.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/ppc405_uc.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/ppc405_uc.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,3452 @@
+/*
+ * QEMU PowerPC 405 embedded processors emulation
+ *
+ * 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 "vl.h"
+#include "ppc405.h"
+
+extern int loglevel;
+extern FILE *logfile;
+
+//#define DEBUG_MMIO
+#define DEBUG_OPBA
+#define DEBUG_SDRAM
+#define DEBUG_GPIO
+#define DEBUG_SERIAL
+#define DEBUG_OCM
+//#define DEBUG_I2C
+#define DEBUG_GPT
+#define DEBUG_MAL
+#define DEBUG_UIC
+#define DEBUG_CLOCKS
+//#define DEBUG_UNASSIGNED
+
+/*****************************************************************************/
+/* Generic PowerPC 405 processor instanciation */
+CPUState *ppc405_init (const unsigned char *cpu_model,
+ clk_setup_t *cpu_clk, clk_setup_t *tb_clk,
+ uint32_t sysclk)
+{
+ CPUState *env;
+ ppc_def_t *def;
+
+ /* init CPUs */
+ env = cpu_init();
+ qemu_register_reset(&cpu_ppc_reset, env);
+ register_savevm("cpu", 0, 3, cpu_save, cpu_load, env);
+ ppc_find_by_name(cpu_model, &def);
+ if (def == NULL) {
+ cpu_abort(env, "Unable to find PowerPC %s CPU definition\n",
+ cpu_model);
+ }
+ cpu_ppc_register(env, def);
+ cpu_clk->cb = NULL; /* We don't care about CPU clock frequency changes */
+ cpu_clk->opaque = env;
+ /* Set time-base frequency to sysclk */
+ tb_clk->cb = ppc_emb_timers_init(env, sysclk);
+ tb_clk->opaque = env;
+ ppc_dcr_init(env, NULL, NULL);
+
+ return env;
+}
+
+ram_addr_t ppc405_set_bootinfo (CPUState *env, ppc4xx_bd_info_t *bd)
+{
+ ram_addr_t bdloc;
+ int i, n;
+
+ /* We put the bd structure at the top of memory */
+ bdloc = bd->bi_memsize - sizeof(struct ppc4xx_bd_info_t);
+ stl_raw(phys_ram_base + bdloc + 0x00, bd->bi_memstart);
+ stl_raw(phys_ram_base + bdloc + 0x04, bd->bi_memsize);
+ stl_raw(phys_ram_base + bdloc + 0x08, bd->bi_flashstart);
+ stl_raw(phys_ram_base + bdloc + 0x0C, bd->bi_flashsize);
+ stl_raw(phys_ram_base + bdloc + 0x10, bd->bi_flashoffset);
+ stl_raw(phys_ram_base + bdloc + 0x14, bd->bi_sramstart);
+ stl_raw(phys_ram_base + bdloc + 0x18, bd->bi_sramsize);
+ stl_raw(phys_ram_base + bdloc + 0x1C, bd->bi_bootflags);
+ stl_raw(phys_ram_base + bdloc + 0x20, bd->bi_ipaddr);
+ for (i = 0; i < 6; i++)
+ stb_raw(phys_ram_base + bdloc + 0x24 + i, bd->bi_enetaddr[i]);
+ stw_raw(phys_ram_base + bdloc + 0x2A, bd->bi_ethspeed);
+ stl_raw(phys_ram_base + bdloc + 0x2C, bd->bi_intfreq);
+ stl_raw(phys_ram_base + bdloc + 0x30, bd->bi_busfreq);
+ stl_raw(phys_ram_base + bdloc + 0x34, bd->bi_baudrate);
+ for (i = 0; i < 4; i++)
+ stb_raw(phys_ram_base + bdloc + 0x38 + i, bd->bi_s_version[i]);
+ for (i = 0; i < 32; i++)
+ stb_raw(phys_ram_base + bdloc + 0x3C + i, bd->bi_s_version[i]);
+ stl_raw(phys_ram_base + bdloc + 0x5C, bd->bi_plb_busfreq);
+ stl_raw(phys_ram_base + bdloc + 0x60, bd->bi_pci_busfreq);
+ for (i = 0; i < 6; i++)
+ stb_raw(phys_ram_base + bdloc + 0x64 + i, bd->bi_pci_enetaddr[i]);
+ n = 0x6A;
+ if (env->spr[SPR_PVR] == CPU_PPC_405EP) {
+ for (i = 0; i < 6; i++)
+ stb_raw(phys_ram_base + bdloc + n++, bd->bi_pci_enetaddr2[i]);
+ }
+ stl_raw(phys_ram_base + bdloc + n, bd->bi_opbfreq);
+ n += 4;
+ for (i = 0; i < 2; i++) {
+ stl_raw(phys_ram_base + bdloc + n, bd->bi_iic_fast[i]);
+ n += 4;
+ }
+
+ return bdloc;
+}
+
+/*****************************************************************************/
+/* Shared peripherals */
+
+/*****************************************************************************/
+/* Fake device used to map multiple devices in a single memory page */
+#define MMIO_AREA_BITS 8
+#define MMIO_AREA_LEN (1 << MMIO_AREA_BITS)
+#define MMIO_AREA_NB (1 << (TARGET_PAGE_BITS - MMIO_AREA_BITS))
+#define MMIO_IDX(addr) (((addr) >> MMIO_AREA_BITS) & (MMIO_AREA_NB - 1))
+struct ppc4xx_mmio_t {
+ target_phys_addr_t base;
+ CPUReadMemoryFunc **mem_read[MMIO_AREA_NB];
+ CPUWriteMemoryFunc **mem_write[MMIO_AREA_NB];
+ void *opaque[MMIO_AREA_NB];
+};
+
+static uint32_t unassigned_mmio_readb (void *opaque, target_phys_addr_t addr)
+{
+#ifdef DEBUG_UNASSIGNED
+ ppc4xx_mmio_t *mmio;
+
+ mmio = opaque;
+ printf("Unassigned mmio read 0x" PADDRX " base " PADDRX "\n",
+ addr, mmio->base);
+#endif
+
+ return 0;
+}
+
+static void unassigned_mmio_writeb (void *opaque,
+ target_phys_addr_t addr, uint32_t val)
+{
+#ifdef DEBUG_UNASSIGNED
+ ppc4xx_mmio_t *mmio;
+
+ mmio = opaque;
+ printf("Unassigned mmio write 0x" PADDRX " = 0x%x base " PADDRX "\n",
+ addr, val, mmio->base);
+#endif
+}
+
+static CPUReadMemoryFunc *unassigned_mmio_read[3] = {
+ unassigned_mmio_readb,
+ unassigned_mmio_readb,
+ unassigned_mmio_readb,
+};
+
+static CPUWriteMemoryFunc *unassigned_mmio_write[3] = {
+ unassigned_mmio_writeb,
+ unassigned_mmio_writeb,
+ unassigned_mmio_writeb,
+};
+
+static uint32_t mmio_readlen (ppc4xx_mmio_t *mmio,
+ target_phys_addr_t addr, int len)
+{
+ CPUReadMemoryFunc **mem_read;
+ uint32_t ret;
+ int idx;
+
+ idx = MMIO_IDX(addr - mmio->base);
+#if defined(DEBUG_MMIO)
+ printf("%s: mmio %p len %d addr " PADDRX " idx %d\n", __func__,
+ mmio, len, addr, idx);
+#endif
+ mem_read = mmio->mem_read[idx];
+ ret = (*mem_read[len])(mmio->opaque[idx], addr - mmio->base);
+
+ return ret;
+}
+
+static void mmio_writelen (ppc4xx_mmio_t *mmio,
+ target_phys_addr_t addr, uint32_t value, int len)
+{
+ CPUWriteMemoryFunc **mem_write;
+ int idx;
+
+ idx = MMIO_IDX(addr - mmio->base);
+#if defined(DEBUG_MMIO)
+ printf("%s: mmio %p len %d addr " PADDRX " idx %d value %08x\n", __func__,
+ mmio, len, addr, idx, value);
+#endif
+ mem_write = mmio->mem_write[idx];
+ (*mem_write[len])(mmio->opaque[idx], addr - mmio->base, value);
+}
+
+static uint32_t mmio_readb (void *opaque, target_phys_addr_t addr)
+{
+#if defined(DEBUG_MMIO)
+ printf("%s: addr " PADDRX "\n", __func__, addr);
+#endif
+
+ return mmio_readlen(opaque, addr, 0);
+}
+
+static void mmio_writeb (void *opaque,
+ target_phys_addr_t addr, uint32_t value)
+{
+#if defined(DEBUG_MMIO)
+ printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value);
+#endif
+ mmio_writelen(opaque, addr, value, 0);
+}
+
+static uint32_t mmio_readw (void *opaque, target_phys_addr_t addr)
+{
+#if defined(DEBUG_MMIO)
+ printf("%s: addr " PADDRX "\n", __func__, addr);
+#endif
+
+ return mmio_readlen(opaque, addr, 1);
+}
+
+static void mmio_writew (void *opaque,
+ target_phys_addr_t addr, uint32_t value)
+{
+#if defined(DEBUG_MMIO)
+ printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value);
+#endif
+ mmio_writelen(opaque, addr, value, 1);
+}
+
+static uint32_t mmio_readl (void *opaque, target_phys_addr_t addr)
+{
+#if defined(DEBUG_MMIO)
+ printf("%s: addr " PADDRX "\n", __func__, addr);
+#endif
+
+ return mmio_readlen(opaque, addr, 2);
+}
+
+static void mmio_writel (void *opaque,
+ target_phys_addr_t addr, uint32_t value)
+{
+#if defined(DEBUG_MMIO)
+ printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value);
+#endif
+ mmio_writelen(opaque, addr, value, 2);
+}
+
+static CPUReadMemoryFunc *mmio_read[] = {
+ &mmio_readb,
+ &mmio_readw,
+ &mmio_readl,
+};
+
+static CPUWriteMemoryFunc *mmio_write[] = {
+ &mmio_writeb,
+ &mmio_writew,
+ &mmio_writel,
+};
+
+int ppc4xx_mmio_register (CPUState *env, ppc4xx_mmio_t *mmio,
+ target_phys_addr_t offset, uint32_t len,
+ CPUReadMemoryFunc **mem_read,
+ CPUWriteMemoryFunc **mem_write, void *opaque)
+{
+ uint32_t end;
+ int idx, eidx;
+
+ if ((offset + len) > TARGET_PAGE_SIZE)
+ return -1;
+ idx = MMIO_IDX(offset);
+ end = offset + len - 1;
+ eidx = MMIO_IDX(end);
+#if defined(DEBUG_MMIO)
+ printf("%s: offset %08x len %08x %08x %d %d\n", __func__, offset, len,
+ end, idx, eidx);
+#endif
+ for (; idx <= eidx; idx++) {
+ mmio->mem_read[idx] = mem_read;
+ mmio->mem_write[idx] = mem_write;
+ mmio->opaque[idx] = opaque;
+ }
+
+ return 0;
+}
+
+ppc4xx_mmio_t *ppc4xx_mmio_init (CPUState *env, target_phys_addr_t base)
+{
+ ppc4xx_mmio_t *mmio;
+ int mmio_memory;
+
+ mmio = qemu_mallocz(sizeof(ppc4xx_mmio_t));
+ if (mmio != NULL) {
+ mmio->base = base;
+ mmio_memory = cpu_register_io_memory(0, mmio_read, mmio_write, mmio);
+#if defined(DEBUG_MMIO)
+ printf("%s: %p base %08x len %08x %d\n", __func__,
+ mmio, base, TARGET_PAGE_SIZE, mmio_memory);
+#endif
+ cpu_register_physical_memory(base, TARGET_PAGE_SIZE, mmio_memory);
+ ppc4xx_mmio_register(env, mmio, 0, TARGET_PAGE_SIZE,
+ unassigned_mmio_read, unassigned_mmio_write,
+ mmio);
+ }
+
+ return mmio;
+}
+
+/*****************************************************************************/
+/* Peripheral local bus arbitrer */
+enum {
+ PLB0_BESR = 0x084,
+ PLB0_BEAR = 0x086,
+ PLB0_ACR = 0x087,
+};
+
+typedef struct ppc4xx_plb_t ppc4xx_plb_t;
+struct ppc4xx_plb_t {
+ uint32_t acr;
+ uint32_t bear;
+ uint32_t besr;
+};
+
+static target_ulong dcr_read_plb (void *opaque, int dcrn)
+{
+ ppc4xx_plb_t *plb;
+ target_ulong ret;
+
+ plb = opaque;
+ switch (dcrn) {
+ case PLB0_ACR:
+ ret = plb->acr;
+ break;
+ case PLB0_BEAR:
+ ret = plb->bear;
+ break;
+ case PLB0_BESR:
+ ret = plb->besr;
+ break;
+ default:
+ /* Avoid gcc warning */
+ ret = 0;
+ break;
+ }
+
+ return ret;
+}
+
+static void dcr_write_plb (void *opaque, int dcrn, target_ulong val)
+{
+ ppc4xx_plb_t *plb;
+
+ plb = opaque;
+ switch (dcrn) {
+ case PLB0_ACR:
+ /* We don't care about the actual parameters written as
+ * we don't manage any priorities on the bus
+ */
+ plb->acr = val & 0xF8000000;
+ break;
+ case PLB0_BEAR:
+ /* Read only */
+ break;
+ case PLB0_BESR:
+ /* Write-clear */
+ plb->besr &= ~val;
+ break;
+ }
+}
+
+static void ppc4xx_plb_reset (void *opaque)
+{
+ ppc4xx_plb_t *plb;
+
+ plb = opaque;
+ plb->acr = 0x00000000;
+ plb->bear = 0x00000000;
+ plb->besr = 0x00000000;
+}
+
+void ppc4xx_plb_init (CPUState *env)
+{
+ ppc4xx_plb_t *plb;
+
+ plb = qemu_mallocz(sizeof(ppc4xx_plb_t));
+ if (plb != NULL) {
+ ppc_dcr_register(env, PLB0_ACR, plb, &dcr_read_plb, &dcr_write_plb);
+ ppc_dcr_register(env, PLB0_BEAR, plb, &dcr_read_plb, &dcr_write_plb);
+ ppc_dcr_register(env, PLB0_BESR, plb, &dcr_read_plb, &dcr_write_plb);
+ ppc4xx_plb_reset(plb);
+ qemu_register_reset(ppc4xx_plb_reset, plb);
+ }
+}
+
+/*****************************************************************************/
+/* PLB to OPB bridge */
+enum {
+ POB0_BESR0 = 0x0A0,
+ POB0_BESR1 = 0x0A2,
+ POB0_BEAR = 0x0A4,
+};
+
+typedef struct ppc4xx_pob_t ppc4xx_pob_t;
+struct ppc4xx_pob_t {
+ uint32_t bear;
+ uint32_t besr[2];
+};
+
+static target_ulong dcr_read_pob (void *opaque, int dcrn)
+{
+ ppc4xx_pob_t *pob;
+ target_ulong ret;
+
+ pob = opaque;
+ switch (dcrn) {
+ case POB0_BEAR:
+ ret = pob->bear;
+ break;
+ case POB0_BESR0:
+ case POB0_BESR1:
+ ret = pob->besr[dcrn - POB0_BESR0];
+ break;
+ default:
+ /* Avoid gcc warning */
+ ret = 0;
+ break;
+ }
+
+ return ret;
+}
+
+static void dcr_write_pob (void *opaque, int dcrn, target_ulong val)
+{
+ ppc4xx_pob_t *pob;
+
+ pob = opaque;
+ switch (dcrn) {
+ case POB0_BEAR:
+ /* Read only */
+ break;
+ case POB0_BESR0:
+ case POB0_BESR1:
+ /* Write-clear */
+ pob->besr[dcrn - POB0_BESR0] &= ~val;
+ break;
+ }
+}
+
+static void ppc4xx_pob_reset (void *opaque)
+{
+ ppc4xx_pob_t *pob;
+
+ pob = opaque;
+ /* No error */
+ pob->bear = 0x00000000;
+ pob->besr[0] = 0x0000000;
+ pob->besr[1] = 0x0000000;
+}
+
+void ppc4xx_pob_init (CPUState *env)
+{
+ ppc4xx_pob_t *pob;
+
+ pob = qemu_mallocz(sizeof(ppc4xx_pob_t));
+ if (pob != NULL) {
+ ppc_dcr_register(env, POB0_BEAR, pob, &dcr_read_pob, &dcr_write_pob);
+ ppc_dcr_register(env, POB0_BESR0, pob, &dcr_read_pob, &dcr_write_pob);
+ ppc_dcr_register(env, POB0_BESR1, pob, &dcr_read_pob, &dcr_write_pob);
+ qemu_register_reset(ppc4xx_pob_reset, pob);
+ ppc4xx_pob_reset(env);
+ }
+}
+
+/*****************************************************************************/
+/* OPB arbitrer */
+typedef struct ppc4xx_opba_t ppc4xx_opba_t;
+struct ppc4xx_opba_t {
+ target_phys_addr_t base;
+ uint8_t cr;
+ uint8_t pr;
+};
+
+static uint32_t opba_readb (void *opaque, target_phys_addr_t addr)
+{
+ ppc4xx_opba_t *opba;
+ uint32_t ret;
+
+#ifdef DEBUG_OPBA
+ printf("%s: addr " PADDRX "\n", __func__, addr);
+#endif
+ opba = opaque;
+ switch (addr - opba->base) {
+ case 0x00:
+ ret = opba->cr;
+ break;
+ case 0x01:
+ ret = opba->pr;
+ break;
+ default:
+ ret = 0x00;
+ break;
+ }
+
+ return ret;
+}
+
+static void opba_writeb (void *opaque,
+ target_phys_addr_t addr, uint32_t value)
+{
+ ppc4xx_opba_t *opba;
+
+#ifdef DEBUG_OPBA
+ printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value);
+#endif
+ opba = opaque;
+ switch (addr - opba->base) {
+ case 0x00:
+ opba->cr = value & 0xF8;
+ break;
+ case 0x01:
+ opba->pr = value & 0xFF;
+ break;
+ default:
+ break;
+ }
+}
+
+static uint32_t opba_readw (void *opaque, target_phys_addr_t addr)
+{
+ uint32_t ret;
+
+#ifdef DEBUG_OPBA
+ printf("%s: addr " PADDRX "\n", __func__, addr);
+#endif
+ ret = opba_readb(opaque, addr) << 8;
+ ret |= opba_readb(opaque, addr + 1);
+
+ return ret;
+}
+
+static void opba_writew (void *opaque,
+ target_phys_addr_t addr, uint32_t value)
+{
+#ifdef DEBUG_OPBA
+ printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value);
+#endif
+ opba_writeb(opaque, addr, value >> 8);
+ opba_writeb(opaque, addr + 1, value);
+}
+
+static uint32_t opba_readl (void *opaque, target_phys_addr_t addr)
+{
+ uint32_t ret;
+
+#ifdef DEBUG_OPBA
+ printf("%s: addr " PADDRX "\n", __func__, addr);
+#endif
+ ret = opba_readb(opaque, addr) << 24;
+ ret |= opba_readb(opaque, addr + 1) << 16;
+
+ return ret;
+}
+
+static void opba_writel (void *opaque,
+ target_phys_addr_t addr, uint32_t value)
+{
+#ifdef DEBUG_OPBA
+ printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value);
+#endif
+ opba_writeb(opaque, addr, value >> 24);
+ opba_writeb(opaque, addr + 1, value >> 16);
+}
+
+static CPUReadMemoryFunc *opba_read[] = {
+ &opba_readb,
+ &opba_readw,
+ &opba_readl,
+};
+
+static CPUWriteMemoryFunc *opba_write[] = {
+ &opba_writeb,
+ &opba_writew,
+ &opba_writel,
+};
+
+static void ppc4xx_opba_reset (void *opaque)
+{
+ ppc4xx_opba_t *opba;
+
+ opba = opaque;
+ opba->cr = 0x00; /* No dynamic priorities - park disabled */
+ opba->pr = 0x11;
+}
+
+void ppc4xx_opba_init (CPUState *env, ppc4xx_mmio_t *mmio,
+ target_phys_addr_t offset)
+{
+ ppc4xx_opba_t *opba;
+
+ opba = qemu_mallocz(sizeof(ppc4xx_opba_t));
+ if (opba != NULL) {
+ opba->base = offset;
+#ifdef DEBUG_OPBA
+ printf("%s: offset=" PADDRX "\n", __func__, offset);
+#endif
+ ppc4xx_mmio_register(env, mmio, offset, 0x002,
+ opba_read, opba_write, opba);
+ qemu_register_reset(ppc4xx_opba_reset, opba);
+ ppc4xx_opba_reset(opba);
+ }
+}
+
+/*****************************************************************************/
+/* "Universal" Interrupt controller */
+enum {
+ DCR_UICSR = 0x000,
+ DCR_UICSRS = 0x001,
+ DCR_UICER = 0x002,
+ DCR_UICCR = 0x003,
+ DCR_UICPR = 0x004,
+ DCR_UICTR = 0x005,
+ DCR_UICMSR = 0x006,
+ DCR_UICVR = 0x007,
+ DCR_UICVCR = 0x008,
+ DCR_UICMAX = 0x009,
+};
+
+#define UIC_MAX_IRQ 32
+typedef struct ppcuic_t ppcuic_t;
+struct ppcuic_t {
+ uint32_t dcr_base;
+ int use_vectors;
+ uint32_t uicsr; /* Status register */
+ uint32_t uicer; /* Enable register */
+ uint32_t uiccr; /* Critical register */
+ uint32_t uicpr; /* Polarity register */
+ uint32_t uictr; /* Triggering register */
+ uint32_t uicvcr; /* Vector configuration register */
+ uint32_t uicvr;
+ qemu_irq *irqs;
+};
+
+static void ppcuic_trigger_irq (ppcuic_t *uic)
+{
+ uint32_t ir, cr;
+ int start, end, inc, i;
+
+ /* Trigger interrupt if any is pending */
+ ir = uic->uicsr & uic->uicer & (~uic->uiccr);
+ cr = uic->uicsr & uic->uicer & uic->uiccr;
+#ifdef DEBUG_UIC
+ if (loglevel & CPU_LOG_INT) {
+ fprintf(logfile, "%s: uicsr %08x uicer %08x uiccr %08x\n"
+ " %08x ir %08x cr %08x\n", __func__,
+ uic->uicsr, uic->uicer, uic->uiccr,
+ uic->uicsr & uic->uicer, ir, cr);
+ }
+#endif
+ if (ir != 0x0000000) {
+#ifdef DEBUG_UIC
+ if (loglevel & CPU_LOG_INT) {
+ fprintf(logfile, "Raise UIC interrupt\n");
+ }
+#endif
+ qemu_irq_raise(uic->irqs[PPCUIC_OUTPUT_INT]);
+ } else {
+#ifdef DEBUG_UIC
+ if (loglevel & CPU_LOG_INT) {
+ fprintf(logfile, "Lower UIC interrupt\n");
+ }
+#endif
+ qemu_irq_lower(uic->irqs[PPCUIC_OUTPUT_INT]);
+ }
+ /* Trigger critical interrupt if any is pending and update vector */
+ if (cr != 0x0000000) {
+ qemu_irq_raise(uic->irqs[PPCUIC_OUTPUT_CINT]);
+ if (uic->use_vectors) {
+ /* Compute critical IRQ vector */
+ if (uic->uicvcr & 1) {
+ start = 31;
+ end = 0;
+ inc = -1;
+ } else {
+ start = 0;
+ end = 31;
+ inc = 1;
+ }
+ uic->uicvr = uic->uicvcr & 0xFFFFFFFC;
+ for (i = start; i <= end; i += inc) {
+ if (cr & (1 << i)) {
+ uic->uicvr += (i - start) * 512 * inc;
+ break;
+ }
+ }
+ }
+#ifdef DEBUG_UIC
+ if (loglevel & CPU_LOG_INT) {
+ fprintf(logfile, "Raise UIC critical interrupt - vector %08x\n",
+ uic->uicvr);
+ }
+#endif
+ } else {
+#ifdef DEBUG_UIC
+ if (loglevel & CPU_LOG_INT) {
+ fprintf(logfile, "Lower UIC critical interrupt\n");
+ }
+#endif
+ qemu_irq_lower(uic->irqs[PPCUIC_OUTPUT_CINT]);
+ uic->uicvr = 0x00000000;
+ }
+}
+
+static void ppcuic_set_irq (void *opaque, int irq_num, int level)
+{
+ ppcuic_t *uic;
+ uint32_t mask, sr;
+
+ uic = opaque;
+ mask = 1 << irq_num;
+#ifdef DEBUG_UIC
+ if (loglevel & CPU_LOG_INT) {
+ fprintf(logfile, "%s: irq %d level %d uicsr %08x mask %08x => %08x "
+ "%08x\n", __func__, irq_num, level,
+ uic->uicsr, mask, uic->uicsr & mask, level << irq_num);
+ }
+#endif
+ if (irq_num < 0 || irq_num > 31)
+ return;
+ sr = uic->uicsr;
+ if (!(uic->uicpr & mask)) {
+ /* Negatively asserted IRQ */
+ level = level == 0 ? 1 : 0;
+ }
+ /* Update status register */
+ if (uic->uictr & mask) {
+ /* Edge sensitive interrupt */
+ if (level == 1)
+ uic->uicsr |= mask;
+ } else {
+ /* Level sensitive interrupt */
+ if (level == 1)
+ uic->uicsr |= mask;
+ else
+ uic->uicsr &= ~mask;
+ }
+#ifdef DEBUG_UIC
+ if (loglevel & CPU_LOG_INT) {
+ fprintf(logfile, "%s: irq %d level %d sr %08x => %08x\n", __func__,
+ irq_num, level, uic->uicsr, sr);
+ }
+#endif
+ if (sr != uic->uicsr)
+ ppcuic_trigger_irq(uic);
+}
+
+static target_ulong dcr_read_uic (void *opaque, int dcrn)
+{
+ ppcuic_t *uic;
+ target_ulong ret;
+
+ uic = opaque;
+ dcrn -= uic->dcr_base;
+ switch (dcrn) {
+ case DCR_UICSR:
+ case DCR_UICSRS:
+ ret = uic->uicsr;
+ break;
+ case DCR_UICER:
+ ret = uic->uicer;
+ break;
+ case DCR_UICCR:
+ ret = uic->uiccr;
+ break;
+ case DCR_UICPR:
+ ret = uic->uicpr;
+ break;
+ case DCR_UICTR:
+ ret = uic->uictr;
+ break;
+ case DCR_UICMSR:
+ ret = uic->uicsr & uic->uicer;
+ break;
+ case DCR_UICVR:
+ if (!uic->use_vectors)
+ goto no_read;
+ ret = uic->uicvr;
+ break;
+ case DCR_UICVCR:
+ if (!uic->use_vectors)
+ goto no_read;
+ ret = uic->uicvcr;
+ break;
+ default:
+ no_read:
+ ret = 0x00000000;
+ break;
+ }
+
+ return ret;
+}
+
+static void dcr_write_uic (void *opaque, int dcrn, target_ulong val)
+{
+ ppcuic_t *uic;
+
+ uic = opaque;
+ dcrn -= uic->dcr_base;
+#ifdef DEBUG_UIC
+ if (loglevel & CPU_LOG_INT) {
+ fprintf(logfile, "%s: dcr %d val " ADDRX "\n", __func__, dcrn, val);
+ }
+#endif
+ switch (dcrn) {
+ case DCR_UICSR:
+ uic->uicsr &= ~val;
+ ppcuic_trigger_irq(uic);
+ break;
+ case DCR_UICSRS:
+ uic->uicsr |= val;
+ ppcuic_trigger_irq(uic);
+ break;
+ case DCR_UICER:
+ uic->uicer = val;
+ ppcuic_trigger_irq(uic);
+ break;
+ case DCR_UICCR:
+ uic->uiccr = val;
+ ppcuic_trigger_irq(uic);
+ break;
+ case DCR_UICPR:
+ uic->uicpr = val;
+ ppcuic_trigger_irq(uic);
+ break;
+ case DCR_UICTR:
+ uic->uictr = val;
+ ppcuic_trigger_irq(uic);
+ break;
+ case DCR_UICMSR:
+ break;
+ case DCR_UICVR:
+ break;
+ case DCR_UICVCR:
+ uic->uicvcr = val & 0xFFFFFFFD;
+ ppcuic_trigger_irq(uic);
+ break;
+ }
+}
+
+static void ppcuic_reset (void *opaque)
+{
+ ppcuic_t *uic;
+
+ uic = opaque;
+ uic->uiccr = 0x00000000;
+ uic->uicer = 0x00000000;
+ uic->uicpr = 0x00000000;
+ uic->uicsr = 0x00000000;
+ uic->uictr = 0x00000000;
+ if (uic->use_vectors) {
+ uic->uicvcr = 0x00000000;
+ uic->uicvr = 0x0000000;
+ }
+}
+
+qemu_irq *ppcuic_init (CPUState *env, qemu_irq *irqs,
+ uint32_t dcr_base, int has_ssr, int has_vr)
+{
+ ppcuic_t *uic;
+ int i;
+
+ uic = qemu_mallocz(sizeof(ppcuic_t));
+ if (uic != NULL) {
+ uic->dcr_base = dcr_base;
+ uic->irqs = irqs;
+ if (has_vr)
+ uic->use_vectors = 1;
+ for (i = 0; i < DCR_UICMAX; i++) {
+ ppc_dcr_register(env, dcr_base + i, uic,
+ &dcr_read_uic, &dcr_write_uic);
+ }
+ qemu_register_reset(ppcuic_reset, uic);
+ ppcuic_reset(uic);
+ }
+
+ return qemu_allocate_irqs(&ppcuic_set_irq, uic, UIC_MAX_IRQ);
+}
+
+/*****************************************************************************/
+/* Code decompression controller */
+/* XXX: TODO */
+
+/*****************************************************************************/
+/* SDRAM controller */
+typedef struct ppc4xx_sdram_t ppc4xx_sdram_t;
+struct ppc4xx_sdram_t {
+ uint32_t addr;
+ int nbanks;
+ target_ulong ram_bases[4];
+ target_ulong ram_sizes[4];
+ uint32_t besr0;
+ uint32_t besr1;
+ uint32_t bear;
+ uint32_t cfg;
+ uint32_t status;
+ uint32_t rtr;
+ uint32_t pmit;
+ uint32_t bcr[4];
+ uint32_t tr;
+ uint32_t ecccfg;
+ uint32_t eccesr;
+ qemu_irq irq;
+};
+
+enum {
+ SDRAM0_CFGADDR = 0x010,
+ SDRAM0_CFGDATA = 0x011,
+};
+
+static uint32_t sdram_bcr (target_ulong ram_base, target_ulong ram_size)
+{
+ uint32_t bcr;
+
+ switch (ram_size) {
+ case (4 * 1024 * 1024):
+ bcr = 0x00000000;
+ break;
+ case (8 * 1024 * 1024):
+ bcr = 0x00020000;
+ break;
+ case (16 * 1024 * 1024):
+ bcr = 0x00040000;
+ break;
+ case (32 * 1024 * 1024):
+ bcr = 0x00060000;
+ break;
+ case (64 * 1024 * 1024):
+ bcr = 0x00080000;
+ break;
+ case (128 * 1024 * 1024):
+ bcr = 0x000A0000;
+ break;
+ case (256 * 1024 * 1024):
+ bcr = 0x000C0000;
+ break;
+ default:
+ printf("%s: invalid RAM size " TARGET_FMT_ld "\n", __func__, ram_size);
+ return 0x00000000;
+ }
+ bcr |= ram_base & 0xFF800000;
+ bcr |= 1;
+
+ return bcr;
+}
+
+static inline target_ulong sdram_base (uint32_t bcr)
+{
+ return bcr & 0xFF800000;
+}
+
+static target_ulong sdram_size (uint32_t bcr)
+{
+ target_ulong size;
+ int sh;
+
+ sh = (bcr >> 17) & 0x7;
+ if (sh == 7)
+ size = -1;
+ else
+ size = (4 * 1024 * 1024) << sh;
+
+ return size;
+}
+
+static void sdram_set_bcr (uint32_t *bcrp, uint32_t bcr, int enabled)
+{
+ if (*bcrp & 0x00000001) {
+ /* Unmap RAM */
+#ifdef DEBUG_SDRAM
+ printf("%s: unmap RAM area " ADDRX " " ADDRX "\n", __func__,
+ sdram_base(*bcrp), sdram_size(*bcrp));
+#endif
+ cpu_register_physical_memory(sdram_base(*bcrp), sdram_size(*bcrp),
+ IO_MEM_UNASSIGNED);
+ }
+ *bcrp = bcr & 0xFFDEE001;
+ if (enabled && (bcr & 0x00000001)) {
+#ifdef DEBUG_SDRAM
+ printf("%s: Map RAM area " ADDRX " " ADDRX "\n", __func__,
+ sdram_base(bcr), sdram_size(bcr));
+#endif
+ cpu_register_physical_memory(sdram_base(bcr), sdram_size(bcr),
+ sdram_base(bcr) | IO_MEM_RAM);
+ }
+}
+
+static void sdram_map_bcr (ppc4xx_sdram_t *sdram)
+{
+ int i;
+
+ for (i = 0; i < sdram->nbanks; i++) {
+ if (sdram->ram_sizes[i] != 0) {
+ sdram_set_bcr(&sdram->bcr[i],
+ sdram_bcr(sdram->ram_bases[i], sdram->ram_sizes[i]),
+ 1);
+ } else {
+ sdram_set_bcr(&sdram->bcr[i], 0x00000000, 0);
+ }
+ }
+}
+
+static void sdram_unmap_bcr (ppc4xx_sdram_t *sdram)
+{
+ int i;
+
+ for (i = 0; i < sdram->nbanks; i++) {
+#ifdef DEBUG_SDRAM
+ printf("%s: Unmap RAM area " ADDRX " " ADDRX "\n", __func__,
+ sdram_base(sdram->bcr[i]), sdram_size(sdram->bcr[i]));
+#endif
+ cpu_register_physical_memory(sdram_base(sdram->bcr[i]),
+ sdram_size(sdram->bcr[i]),
+ IO_MEM_UNASSIGNED);
+ }
+}
+
+static target_ulong dcr_read_sdram (void *opaque, int dcrn)
+{
+ ppc4xx_sdram_t *sdram;
+ target_ulong ret;
+
+ sdram = opaque;
+ switch (dcrn) {
+ case SDRAM0_CFGADDR:
+ ret = sdram->addr;
+ break;
+ case SDRAM0_CFGDATA:
+ switch (sdram->addr) {
+ case 0x00: /* SDRAM_BESR0 */
+ ret = sdram->besr0;
+ break;
+ case 0x08: /* SDRAM_BESR1 */
+ ret = sdram->besr1;
+ break;
+ case 0x10: /* SDRAM_BEAR */
+ ret = sdram->bear;
+ break;
+ case 0x20: /* SDRAM_CFG */
+ ret = sdram->cfg;
+ break;
+ case 0x24: /* SDRAM_STATUS */
+ ret = sdram->status;
+ break;
+ case 0x30: /* SDRAM_RTR */
+ ret = sdram->rtr;
+ break;
+ case 0x34: /* SDRAM_PMIT */
+ ret = sdram->pmit;
+ break;
+ case 0x40: /* SDRAM_B0CR */
+ ret = sdram->bcr[0];
+ break;
+ case 0x44: /* SDRAM_B1CR */
+ ret = sdram->bcr[1];
+ break;
+ case 0x48: /* SDRAM_B2CR */
+ ret = sdram->bcr[2];
+ break;
+ case 0x4C: /* SDRAM_B3CR */
+ ret = sdram->bcr[3];
+ break;
+ case 0x80: /* SDRAM_TR */
+ ret = -1; /* ? */
+ break;
+ case 0x94: /* SDRAM_ECCCFG */
+ ret = sdram->ecccfg;
+ break;
+ case 0x98: /* SDRAM_ECCESR */
+ ret = sdram->eccesr;
+ break;
+ default: /* Error */
+ ret = -1;
+ break;
+ }
+ break;
+ default:
+ /* Avoid gcc warning */
+ ret = 0x00000000;
+ break;
+ }
+
+ return ret;
+}
+
+static void dcr_write_sdram (void *opaque, int dcrn, target_ulong val)
+{
+ ppc4xx_sdram_t *sdram;
+
+ sdram = opaque;
+ switch (dcrn) {
+ case SDRAM0_CFGADDR:
+ sdram->addr = val;
+ break;
+ case SDRAM0_CFGDATA:
+ switch (sdram->addr) {
+ case 0x00: /* SDRAM_BESR0 */
+ sdram->besr0 &= ~val;
+ break;
+ case 0x08: /* SDRAM_BESR1 */
+ sdram->besr1 &= ~val;
+ break;
+ case 0x10: /* SDRAM_BEAR */
+ sdram->bear = val;
+ break;
+ case 0x20: /* SDRAM_CFG */
+ val &= 0xFFE00000;
+ if (!(sdram->cfg & 0x80000000) && (val & 0x80000000)) {
+#ifdef DEBUG_SDRAM
+ printf("%s: enable SDRAM controller\n", __func__);
+#endif
+ /* validate all RAM mappings */
+ sdram_map_bcr(sdram);
+ sdram->status &= ~0x80000000;
+ } else if ((sdram->cfg & 0x80000000) && !(val & 0x80000000)) {
+#ifdef DEBUG_SDRAM
+ printf("%s: disable SDRAM controller\n", __func__);
+#endif
+ /* invalidate all RAM mappings */
+ sdram_unmap_bcr(sdram);
+ sdram->status |= 0x80000000;
+ }
+ if (!(sdram->cfg & 0x40000000) && (val & 0x40000000))
+ sdram->status |= 0x40000000;
+ else if ((sdram->cfg & 0x40000000) && !(val & 0x40000000))
+ sdram->status &= ~0x40000000;
+ sdram->cfg = val;
+ break;
+ case 0x24: /* SDRAM_STATUS */
+ /* Read-only register */
+ break;
+ case 0x30: /* SDRAM_RTR */
+ sdram->rtr = val & 0x3FF80000;
+ break;
+ case 0x34: /* SDRAM_PMIT */
+ sdram->pmit = (val & 0xF8000000) | 0x07C00000;
+ break;
+ case 0x40: /* SDRAM_B0CR */
+ sdram_set_bcr(&sdram->bcr[0], val, sdram->cfg & 0x80000000);
+ break;
+ case 0x44: /* SDRAM_B1CR */
+ sdram_set_bcr(&sdram->bcr[1], val, sdram->cfg & 0x80000000);
+ break;
+ case 0x48: /* SDRAM_B2CR */
+ sdram_set_bcr(&sdram->bcr[2], val, sdram->cfg & 0x80000000);
+ break;
+ case 0x4C: /* SDRAM_B3CR */
+ sdram_set_bcr(&sdram->bcr[3], val, sdram->cfg & 0x80000000);
+ break;
+ case 0x80: /* SDRAM_TR */
+ sdram->tr = val & 0x018FC01F;
+ break;
+ case 0x94: /* SDRAM_ECCCFG */
+ sdram->ecccfg = val & 0x00F00000;
+ break;
+ case 0x98: /* SDRAM_ECCESR */
+ val &= 0xFFF0F000;
+ if (sdram->eccesr == 0 && val != 0)
+ qemu_irq_raise(sdram->irq);
+ else if (sdram->eccesr != 0 && val == 0)
+ qemu_irq_lower(sdram->irq);
+ sdram->eccesr = val;
+ break;
+ default: /* Error */
+ break;
+ }
+ break;
+ }
+}
+
+static void sdram_reset (void *opaque)
+{
+ ppc4xx_sdram_t *sdram;
+
+ sdram = opaque;
+ sdram->addr = 0x00000000;
+ sdram->bear = 0x00000000;
+ sdram->besr0 = 0x00000000; /* No error */
+ sdram->besr1 = 0x00000000; /* No error */
+ sdram->cfg = 0x00000000;
+ sdram->ecccfg = 0x00000000; /* No ECC */
+ sdram->eccesr = 0x00000000; /* No error */
+ sdram->pmit = 0x07C00000;
+ sdram->rtr = 0x05F00000;
+ sdram->tr = 0x00854009;
+ /* We pre-initialize RAM banks */
+ sdram->status = 0x00000000;
+ sdram->cfg = 0x00800000;
+ sdram_unmap_bcr(sdram);
+}
+
+void ppc405_sdram_init (CPUState *env, qemu_irq irq, int nbanks,
+ target_ulong *ram_bases, target_ulong *ram_sizes,
+ int do_init)
+{
+ ppc4xx_sdram_t *sdram;
+
+ sdram = qemu_mallocz(sizeof(ppc4xx_sdram_t));
+ if (sdram != NULL) {
+ sdram->irq = irq;
+ sdram->nbanks = nbanks;
+ memset(sdram->ram_bases, 0, 4 * sizeof(target_ulong));
+ memcpy(sdram->ram_bases, ram_bases, nbanks * sizeof(target_ulong));
+ memset(sdram->ram_sizes, 0, 4 * sizeof(target_ulong));
+ memcpy(sdram->ram_sizes, ram_sizes, nbanks * sizeof(target_ulong));
+ sdram_reset(sdram);
+ qemu_register_reset(&sdram_reset, sdram);
+ ppc_dcr_register(env, SDRAM0_CFGADDR,
+ sdram, &dcr_read_sdram, &dcr_write_sdram);
+ ppc_dcr_register(env, SDRAM0_CFGDATA,
+ sdram, &dcr_read_sdram, &dcr_write_sdram);
+ if (do_init)
+ sdram_map_bcr(sdram);
+ }
+}
+
+/*****************************************************************************/
+/* Peripheral controller */
+typedef struct ppc4xx_ebc_t ppc4xx_ebc_t;
+struct ppc4xx_ebc_t {
+ uint32_t addr;
+ uint32_t bcr[8];
+ uint32_t bap[8];
+ uint32_t bear;
+ uint32_t besr0;
+ uint32_t besr1;
+ uint32_t cfg;
+};
+
+enum {
+ EBC0_CFGADDR = 0x012,
+ EBC0_CFGDATA = 0x013,
+};
+
+static target_ulong dcr_read_ebc (void *opaque, int dcrn)
+{
+ ppc4xx_ebc_t *ebc;
+ target_ulong ret;
+
+ ebc = opaque;
+ switch (dcrn) {
+ case EBC0_CFGADDR:
+ ret = ebc->addr;
+ break;
+ case EBC0_CFGDATA:
+ switch (ebc->addr) {
+ case 0x00: /* B0CR */
+ ret = ebc->bcr[0];
+ break;
+ case 0x01: /* B1CR */
+ ret = ebc->bcr[1];
+ break;
+ case 0x02: /* B2CR */
+ ret = ebc->bcr[2];
+ break;
+ case 0x03: /* B3CR */
+ ret = ebc->bcr[3];
+ break;
+ case 0x04: /* B4CR */
+ ret = ebc->bcr[4];
+ break;
+ case 0x05: /* B5CR */
+ ret = ebc->bcr[5];
+ break;
+ case 0x06: /* B6CR */
+ ret = ebc->bcr[6];
+ break;
+ case 0x07: /* B7CR */
+ ret = ebc->bcr[7];
+ break;
+ case 0x10: /* B0AP */
+ ret = ebc->bap[0];
+ break;
+ case 0x11: /* B1AP */
+ ret = ebc->bap[1];
+ break;
+ case 0x12: /* B2AP */
+ ret = ebc->bap[2];
+ break;
+ case 0x13: /* B3AP */
+ ret = ebc->bap[3];
+ break;
+ case 0x14: /* B4AP */
+ ret = ebc->bap[4];
+ break;
+ case 0x15: /* B5AP */
+ ret = ebc->bap[5];
+ break;
+ case 0x16: /* B6AP */
+ ret = ebc->bap[6];
+ break;
+ case 0x17: /* B7AP */
+ ret = ebc->bap[7];
+ break;
+ case 0x20: /* BEAR */
+ ret = ebc->bear;
+ break;
+ case 0x21: /* BESR0 */
+ ret = ebc->besr0;
+ break;
+ case 0x22: /* BESR1 */
+ ret = ebc->besr1;
+ break;
+ case 0x23: /* CFG */
+ ret = ebc->cfg;
+ break;
+ default:
+ ret = 0x00000000;
+ break;
+ }
+ default:
+ ret = 0x00000000;
+ break;
+ }
+
+ return ret;
+}
+
+static void dcr_write_ebc (void *opaque, int dcrn, target_ulong val)
+{
+ ppc4xx_ebc_t *ebc;
+
+ ebc = opaque;
+ switch (dcrn) {
+ case EBC0_CFGADDR:
+ ebc->addr = val;
+ break;
+ case EBC0_CFGDATA:
+ switch (ebc->addr) {
+ case 0x00: /* B0CR */
+ break;
+ case 0x01: /* B1CR */
+ break;
+ case 0x02: /* B2CR */
+ break;
+ case 0x03: /* B3CR */
+ break;
+ case 0x04: /* B4CR */
+ break;
+ case 0x05: /* B5CR */
+ break;
+ case 0x06: /* B6CR */
+ break;
+ case 0x07: /* B7CR */
+ break;
+ case 0x10: /* B0AP */
+ break;
+ case 0x11: /* B1AP */
+ break;
+ case 0x12: /* B2AP */
+ break;
+ case 0x13: /* B3AP */
+ break;
+ case 0x14: /* B4AP */
+ break;
+ case 0x15: /* B5AP */
+ break;
+ case 0x16: /* B6AP */
+ break;
+ case 0x17: /* B7AP */
+ break;
+ case 0x20: /* BEAR */
+ break;
+ case 0x21: /* BESR0 */
+ break;
+ case 0x22: /* BESR1 */
+ break;
+ case 0x23: /* CFG */
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static void ebc_reset (void *opaque)
+{
+ ppc4xx_ebc_t *ebc;
+ int i;
+
+ ebc = opaque;
+ ebc->addr = 0x00000000;
+ ebc->bap[0] = 0x7F8FFE80;
+ ebc->bcr[0] = 0xFFE28000;
+ for (i = 0; i < 8; i++) {
+ ebc->bap[i] = 0x00000000;
+ ebc->bcr[i] = 0x00000000;
+ }
+ ebc->besr0 = 0x00000000;
+ ebc->besr1 = 0x00000000;
+ ebc->cfg = 0x80400000;
+}
+
+void ppc405_ebc_init (CPUState *env)
+{
+ ppc4xx_ebc_t *ebc;
+
+ ebc = qemu_mallocz(sizeof(ppc4xx_ebc_t));
+ if (ebc != NULL) {
+ ebc_reset(ebc);
+ qemu_register_reset(&ebc_reset, ebc);
+ ppc_dcr_register(env, EBC0_CFGADDR,
+ ebc, &dcr_read_ebc, &dcr_write_ebc);
+ ppc_dcr_register(env, EBC0_CFGDATA,
+ ebc, &dcr_read_ebc, &dcr_write_ebc);
+ }
+}
+
+/*****************************************************************************/
+/* DMA controller */
+enum {
+ DMA0_CR0 = 0x100,
+ DMA0_CT0 = 0x101,
+ DMA0_DA0 = 0x102,
+ DMA0_SA0 = 0x103,
+ DMA0_SG0 = 0x104,
+ DMA0_CR1 = 0x108,
+ DMA0_CT1 = 0x109,
+ DMA0_DA1 = 0x10A,
+ DMA0_SA1 = 0x10B,
+ DMA0_SG1 = 0x10C,
+ DMA0_CR2 = 0x110,
+ DMA0_CT2 = 0x111,
+ DMA0_DA2 = 0x112,
+ DMA0_SA2 = 0x113,
+ DMA0_SG2 = 0x114,
+ DMA0_CR3 = 0x118,
+ DMA0_CT3 = 0x119,
+ DMA0_DA3 = 0x11A,
+ DMA0_SA3 = 0x11B,
+ DMA0_SG3 = 0x11C,
+ DMA0_SR = 0x120,
+ DMA0_SGC = 0x123,
+ DMA0_SLP = 0x125,
+ DMA0_POL = 0x126,
+};
+
+typedef struct ppc405_dma_t ppc405_dma_t;
+struct ppc405_dma_t {
+ qemu_irq irqs[4];
+ uint32_t cr[4];
+ uint32_t ct[4];
+ uint32_t da[4];
+ uint32_t sa[4];
+ uint32_t sg[4];
+ uint32_t sr;
+ uint32_t sgc;
+ uint32_t slp;
+ uint32_t pol;
+};
+
+static target_ulong dcr_read_dma (void *opaque, int dcrn)
+{
+ ppc405_dma_t *dma;
+
+ dma = opaque;
+
+ return 0;
+}
+
+static void dcr_write_dma (void *opaque, int dcrn, target_ulong val)
+{
+ ppc405_dma_t *dma;
+
+ dma = opaque;
+}
+
+static void ppc405_dma_reset (void *opaque)
+{
+ ppc405_dma_t *dma;
+ int i;
+
+ dma = opaque;
+ for (i = 0; i < 4; i++) {
+ dma->cr[i] = 0x00000000;
+ dma->ct[i] = 0x00000000;
+ dma->da[i] = 0x00000000;
+ dma->sa[i] = 0x00000000;
+ dma->sg[i] = 0x00000000;
+ }
+ dma->sr = 0x00000000;
+ dma->sgc = 0x00000000;
+ dma->slp = 0x7C000000;
+ dma->pol = 0x00000000;
+}
+
+void ppc405_dma_init (CPUState *env, qemu_irq irqs[4])
+{
+ ppc405_dma_t *dma;
+
+ dma = qemu_mallocz(sizeof(ppc405_dma_t));
+ if (dma != NULL) {
+ memcpy(dma->irqs, irqs, 4 * sizeof(qemu_irq));
+ ppc405_dma_reset(dma);
+ qemu_register_reset(&ppc405_dma_reset, dma);
+ ppc_dcr_register(env, DMA0_CR0,
+ dma, &dcr_read_dma, &dcr_write_dma);
+ ppc_dcr_register(env, DMA0_CT0,
+ dma, &dcr_read_dma, &dcr_write_dma);
+ ppc_dcr_register(env, DMA0_DA0,
+ dma, &dcr_read_dma, &dcr_write_dma);
+ ppc_dcr_register(env, DMA0_SA0,
+ dma, &dcr_read_dma, &dcr_write_dma);
+ ppc_dcr_register(env, DMA0_SG0,
+ dma, &dcr_read_dma, &dcr_write_dma);
+ ppc_dcr_register(env, DMA0_CR1,
+ dma, &dcr_read_dma, &dcr_write_dma);
+ ppc_dcr_register(env, DMA0_CT1,
+ dma, &dcr_read_dma, &dcr_write_dma);
+ ppc_dcr_register(env, DMA0_DA1,
+ dma, &dcr_read_dma, &dcr_write_dma);
+ ppc_dcr_register(env, DMA0_SA1,
+ dma, &dcr_read_dma, &dcr_write_dma);
+ ppc_dcr_register(env, DMA0_SG1,
+ dma, &dcr_read_dma, &dcr_write_dma);
+ ppc_dcr_register(env, DMA0_CR2,
+ dma, &dcr_read_dma, &dcr_write_dma);
+ ppc_dcr_register(env, DMA0_CT2,
+ dma, &dcr_read_dma, &dcr_write_dma);
+ ppc_dcr_register(env, DMA0_DA2,
+ dma, &dcr_read_dma, &dcr_write_dma);
+ ppc_dcr_register(env, DMA0_SA2,
+ dma, &dcr_read_dma, &dcr_write_dma);
+ ppc_dcr_register(env, DMA0_SG2,
+ dma, &dcr_read_dma, &dcr_write_dma);
+ ppc_dcr_register(env, DMA0_CR3,
+ dma, &dcr_read_dma, &dcr_write_dma);
+ ppc_dcr_register(env, DMA0_CT3,
+ dma, &dcr_read_dma, &dcr_write_dma);
+ ppc_dcr_register(env, DMA0_DA3,
+ dma, &dcr_read_dma, &dcr_write_dma);
+ ppc_dcr_register(env, DMA0_SA3,
+ dma, &dcr_read_dma, &dcr_write_dma);
+ ppc_dcr_register(env, DMA0_SG3,
+ dma, &dcr_read_dma, &dcr_write_dma);
+ ppc_dcr_register(env, DMA0_SR,
+ dma, &dcr_read_dma, &dcr_write_dma);
+ ppc_dcr_register(env, DMA0_SGC,
+ dma, &dcr_read_dma, &dcr_write_dma);
+ ppc_dcr_register(env, DMA0_SLP,
+ dma, &dcr_read_dma, &dcr_write_dma);
+ ppc_dcr_register(env, DMA0_POL,
+ dma, &dcr_read_dma, &dcr_write_dma);
+ }
+}
+
+/*****************************************************************************/
+/* GPIO */
+typedef struct ppc405_gpio_t ppc405_gpio_t;
+struct ppc405_gpio_t {
+ target_phys_addr_t base;
+ uint32_t or;
+ uint32_t tcr;
+ uint32_t osrh;
+ uint32_t osrl;
+ uint32_t tsrh;
+ uint32_t tsrl;
+ uint32_t odr;
+ uint32_t ir;
+ uint32_t rr1;
+ uint32_t isr1h;
+ uint32_t isr1l;
+};
+
+static uint32_t ppc405_gpio_readb (void *opaque, target_phys_addr_t addr)
+{
+ ppc405_gpio_t *gpio;
+
+ gpio = opaque;
+#ifdef DEBUG_GPIO
+ printf("%s: addr " PADDRX "\n", __func__, addr);
+#endif
+
+ return 0;
+}
+
+static void ppc405_gpio_writeb (void *opaque,
+ target_phys_addr_t addr, uint32_t value)
+{
+ ppc405_gpio_t *gpio;
+
+ gpio = opaque;
+#ifdef DEBUG_GPIO
+ printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value);
+#endif
+}
+
+static uint32_t ppc405_gpio_readw (void *opaque, target_phys_addr_t addr)
+{
+ ppc405_gpio_t *gpio;
+
+ gpio = opaque;
+#ifdef DEBUG_GPIO
+ printf("%s: addr " PADDRX "\n", __func__, addr);
+#endif
+
+ return 0;
+}
+
+static void ppc405_gpio_writew (void *opaque,
+ target_phys_addr_t addr, uint32_t value)
+{
+ ppc405_gpio_t *gpio;
+
+ gpio = opaque;
+#ifdef DEBUG_GPIO
+ printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value);
+#endif
+}
+
+static uint32_t ppc405_gpio_readl (void *opaque, target_phys_addr_t addr)
+{
+ ppc405_gpio_t *gpio;
+
+ gpio = opaque;
+#ifdef DEBUG_GPIO
+ printf("%s: addr " PADDRX "\n", __func__, addr);
+#endif
+
+ return 0;
+}
+
+static void ppc405_gpio_writel (void *opaque,
+ target_phys_addr_t addr, uint32_t value)
+{
+ ppc405_gpio_t *gpio;
+
+ gpio = opaque;
+#ifdef DEBUG_GPIO
+ printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value);
+#endif
+}
+
+static CPUReadMemoryFunc *ppc405_gpio_read[] = {
+ &ppc405_gpio_readb,
+ &ppc405_gpio_readw,
+ &ppc405_gpio_readl,
+};
+
+static CPUWriteMemoryFunc *ppc405_gpio_write[] = {
+ &ppc405_gpio_writeb,
+ &ppc405_gpio_writew,
+ &ppc405_gpio_writel,
+};
+
+static void ppc405_gpio_reset (void *opaque)
+{
+ ppc405_gpio_t *gpio;
+
+ gpio = opaque;
+}
+
+void ppc405_gpio_init (CPUState *env, ppc4xx_mmio_t *mmio,
+ target_phys_addr_t offset)
+{
+ ppc405_gpio_t *gpio;
+
+ gpio = qemu_mallocz(sizeof(ppc405_gpio_t));
+ if (gpio != NULL) {
+ gpio->base = offset;
+ ppc405_gpio_reset(gpio);
+ qemu_register_reset(&ppc405_gpio_reset, gpio);
+#ifdef DEBUG_GPIO
+ printf("%s: offset=" PADDRX "\n", __func__, offset);
+#endif
+ ppc4xx_mmio_register(env, mmio, offset, 0x038,
+ ppc405_gpio_read, ppc405_gpio_write, gpio);
+ }
+}
+
+/*****************************************************************************/
+/* Serial ports */
+static CPUReadMemoryFunc *serial_mm_read[] = {
+ &serial_mm_readb,
+ &serial_mm_readw,
+ &serial_mm_readl,
+};
+
+static CPUWriteMemoryFunc *serial_mm_write[] = {
+ &serial_mm_writeb,
+ &serial_mm_writew,
+ &serial_mm_writel,
+};
+
+void ppc405_serial_init (CPUState *env, ppc4xx_mmio_t *mmio,
+ target_phys_addr_t offset, qemu_irq irq,
+ CharDriverState *chr)
+{
+ void *serial;
+
+#ifdef DEBUG_SERIAL
+ printf("%s: offset=" PADDRX "\n", __func__, offset);
+#endif
+ serial = serial_mm_init(offset, 0, irq, chr, 0);
+ ppc4xx_mmio_register(env, mmio, offset, 0x008,
+ serial_mm_read, serial_mm_write, serial);
+}
+
+/*****************************************************************************/
+/* On Chip Memory */
+enum {
+ OCM0_ISARC = 0x018,
+ OCM0_ISACNTL = 0x019,
+ OCM0_DSARC = 0x01A,
+ OCM0_DSACNTL = 0x01B,
+};
+
+typedef struct ppc405_ocm_t ppc405_ocm_t;
+struct ppc405_ocm_t {
+ target_ulong offset;
+ uint32_t isarc;
+ uint32_t isacntl;
+ uint32_t dsarc;
+ uint32_t dsacntl;
+};
+
+static void ocm_update_mappings (ppc405_ocm_t *ocm,
+ uint32_t isarc, uint32_t isacntl,
+ uint32_t dsarc, uint32_t dsacntl)
+{
+#ifdef DEBUG_OCM
+ printf("OCM update ISA %08x %08x (%08x %08x) DSA %08x %08x (%08x %08x)\n",
+ isarc, isacntl, dsarc, dsacntl,
+ ocm->isarc, ocm->isacntl, ocm->dsarc, ocm->dsacntl);
+#endif
+ if (ocm->isarc != isarc ||
+ (ocm->isacntl & 0x80000000) != (isacntl & 0x80000000)) {
+ if (ocm->isacntl & 0x80000000) {
+ /* Unmap previously assigned memory region */
+ printf("OCM unmap ISA %08x\n", ocm->isarc);
+ cpu_register_physical_memory(ocm->isarc, 0x04000000,
+ IO_MEM_UNASSIGNED);
+ }
+ if (isacntl & 0x80000000) {
+ /* Map new instruction memory region */
+#ifdef DEBUG_OCM
+ printf("OCM map ISA %08x\n", isarc);
+#endif
+ cpu_register_physical_memory(isarc, 0x04000000,
+ ocm->offset | IO_MEM_RAM);
+ }
+ }
+ if (ocm->dsarc != dsarc ||
+ (ocm->dsacntl & 0x80000000) != (dsacntl & 0x80000000)) {
+ if (ocm->dsacntl & 0x80000000) {
+ /* Beware not to unmap the region we just mapped */
+ if (!(isacntl & 0x80000000) || ocm->dsarc != isarc) {
+ /* Unmap previously assigned memory region */
+#ifdef DEBUG_OCM
+ printf("OCM unmap DSA %08x\n", ocm->dsarc);
+#endif
+ cpu_register_physical_memory(ocm->dsarc, 0x04000000,
+ IO_MEM_UNASSIGNED);
+ }
+ }
+ if (dsacntl & 0x80000000) {
+ /* Beware not to remap the region we just mapped */
+ if (!(isacntl & 0x80000000) || dsarc != isarc) {
+ /* Map new data memory region */
+#ifdef DEBUG_OCM
+ printf("OCM map DSA %08x\n", dsarc);
+#endif
+ cpu_register_physical_memory(dsarc, 0x04000000,
+ ocm->offset | IO_MEM_RAM);
+ }
+ }
+ }
+}
+
+static target_ulong dcr_read_ocm (void *opaque, int dcrn)
+{
+ ppc405_ocm_t *ocm;
+ target_ulong ret;
+
+ ocm = opaque;
+ switch (dcrn) {
+ case OCM0_ISARC:
+ ret = ocm->isarc;
+ break;
+ case OCM0_ISACNTL:
+ ret = ocm->isacntl;
+ break;
+ case OCM0_DSARC:
+ ret = ocm->dsarc;
+ break;
+ case OCM0_DSACNTL:
+ ret = ocm->dsacntl;
+ break;
+ default:
+ ret = 0;
+ break;
+ }
+
+ return ret;
+}
+
+static void dcr_write_ocm (void *opaque, int dcrn, target_ulong val)
+{
+ ppc405_ocm_t *ocm;
+ uint32_t isarc, dsarc, isacntl, dsacntl;
+
+ ocm = opaque;
+ isarc = ocm->isarc;
+ dsarc = ocm->dsarc;
+ isacntl = ocm->isacntl;
+ dsacntl = ocm->dsacntl;
+ switch (dcrn) {
+ case OCM0_ISARC:
+ isarc = val & 0xFC000000;
+ break;
+ case OCM0_ISACNTL:
+ isacntl = val & 0xC0000000;
+ break;
+ case OCM0_DSARC:
+ isarc = val & 0xFC000000;
+ break;
+ case OCM0_DSACNTL:
+ isacntl = val & 0xC0000000;
+ break;
+ }
+ ocm_update_mappings(ocm, isarc, isacntl, dsarc, dsacntl);
+ ocm->isarc = isarc;
+ ocm->dsarc = dsarc;
+ ocm->isacntl = isacntl;
+ ocm->dsacntl = dsacntl;
+}
+
+static void ocm_reset (void *opaque)
+{
+ ppc405_ocm_t *ocm;
+ uint32_t isarc, dsarc, isacntl, dsacntl;
+
+ ocm = opaque;
+ isarc = 0x00000000;
+ isacntl = 0x00000000;
+ dsarc = 0x00000000;
+ dsacntl = 0x00000000;
+ ocm_update_mappings(ocm, isarc, isacntl, dsarc, dsacntl);
+ ocm->isarc = isarc;
+ ocm->dsarc = dsarc;
+ ocm->isacntl = isacntl;
+ ocm->dsacntl = dsacntl;
+}
+
+void ppc405_ocm_init (CPUState *env, unsigned long offset)
+{
+ ppc405_ocm_t *ocm;
+
+ ocm = qemu_mallocz(sizeof(ppc405_ocm_t));
+ if (ocm != NULL) {
+ ocm->offset = offset;
+ ocm_reset(ocm);
+ qemu_register_reset(&ocm_reset, ocm);
+ ppc_dcr_register(env, OCM0_ISARC,
+ ocm, &dcr_read_ocm, &dcr_write_ocm);
+ ppc_dcr_register(env, OCM0_ISACNTL,
+ ocm, &dcr_read_ocm, &dcr_write_ocm);
+ ppc_dcr_register(env, OCM0_DSARC,
+ ocm, &dcr_read_ocm, &dcr_write_ocm);
+ ppc_dcr_register(env, OCM0_DSACNTL,
+ ocm, &dcr_read_ocm, &dcr_write_ocm);
+ }
+}
+
+/*****************************************************************************/
+/* I2C controller */
+typedef struct ppc4xx_i2c_t ppc4xx_i2c_t;
+struct ppc4xx_i2c_t {
+ target_phys_addr_t base;
+ qemu_irq irq;
+ uint8_t mdata;
+ uint8_t lmadr;
+ uint8_t hmadr;
+ uint8_t cntl;
+ uint8_t mdcntl;
+ uint8_t sts;
+ uint8_t extsts;
+ uint8_t sdata;
+ uint8_t lsadr;
+ uint8_t hsadr;
+ uint8_t clkdiv;
+ uint8_t intrmsk;
+ uint8_t xfrcnt;
+ uint8_t xtcntlss;
+ uint8_t directcntl;
+};
+
+static uint32_t ppc4xx_i2c_readb (void *opaque, target_phys_addr_t addr)
+{
+ ppc4xx_i2c_t *i2c;
+ uint32_t ret;
+
+#ifdef DEBUG_I2C
+ printf("%s: addr " PADDRX "\n", __func__, addr);
+#endif
+ i2c = opaque;
+ switch (addr - i2c->base) {
+ case 0x00:
+ // i2c_readbyte(&i2c->mdata);
+ ret = i2c->mdata;
+ break;
+ case 0x02:
+ ret = i2c->sdata;
+ break;
+ case 0x04:
+ ret = i2c->lmadr;
+ break;
+ case 0x05:
+ ret = i2c->hmadr;
+ break;
+ case 0x06:
+ ret = i2c->cntl;
+ break;
+ case 0x07:
+ ret = i2c->mdcntl;
+ break;
+ case 0x08:
+ ret = i2c->sts;
+ break;
+ case 0x09:
+ ret = i2c->extsts;
+ break;
+ case 0x0A:
+ ret = i2c->lsadr;
+ break;
+ case 0x0B:
+ ret = i2c->hsadr;
+ break;
+ case 0x0C:
+ ret = i2c->clkdiv;
+ break;
+ case 0x0D:
+ ret = i2c->intrmsk;
+ break;
+ case 0x0E:
+ ret = i2c->xfrcnt;
+ break;
+ case 0x0F:
+ ret = i2c->xtcntlss;
+ break;
+ case 0x10:
+ ret = i2c->directcntl;
+ break;
+ default:
+ ret = 0x00;
+ break;
+ }
+#ifdef DEBUG_I2C
+ printf("%s: addr " PADDRX " %02x\n", __func__, addr, ret);
+#endif
+
+ return ret;
+}
+
+static void ppc4xx_i2c_writeb (void *opaque,
+ target_phys_addr_t addr, uint32_t value)
+{
+ ppc4xx_i2c_t *i2c;
+
+#ifdef DEBUG_I2C
+ printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value);
+#endif
+ i2c = opaque;
+ switch (addr - i2c->base) {
+ case 0x00:
+ i2c->mdata = value;
+ // i2c_sendbyte(&i2c->mdata);
+ break;
+ case 0x02:
+ i2c->sdata = value;
+ break;
+ case 0x04:
+ i2c->lmadr = value;
+ break;
+ case 0x05:
+ i2c->hmadr = value;
+ break;
+ case 0x06:
+ i2c->cntl = value;
+ break;
+ case 0x07:
+ i2c->mdcntl = value & 0xDF;
+ break;
+ case 0x08:
+ i2c->sts &= ~(value & 0x0A);
+ break;
+ case 0x09:
+ i2c->extsts &= ~(value & 0x8F);
+ break;
+ case 0x0A:
+ i2c->lsadr = value;
+ break;
+ case 0x0B:
+ i2c->hsadr = value;
+ break;
+ case 0x0C:
+ i2c->clkdiv = value;
+ break;
+ case 0x0D:
+ i2c->intrmsk = value;
+ break;
+ case 0x0E:
+ i2c->xfrcnt = value & 0x77;
+ break;
+ case 0x0F:
+ i2c->xtcntlss = value;
+ break;
+ case 0x10:
+ i2c->directcntl = value & 0x7;
+ break;
+ }
+}
+
+static uint32_t ppc4xx_i2c_readw (void *opaque, target_phys_addr_t addr)
+{
+ uint32_t ret;
+
+#ifdef DEBUG_I2C
+ printf("%s: addr " PADDRX "\n", __func__, addr);
+#endif
+ ret = ppc4xx_i2c_readb(opaque, addr) << 8;
+ ret |= ppc4xx_i2c_readb(opaque, addr + 1);
+
+ return ret;
+}
+
+static void ppc4xx_i2c_writew (void *opaque,
+ target_phys_addr_t addr, uint32_t value)
+{
+#ifdef DEBUG_I2C
+ printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value);
+#endif
+ ppc4xx_i2c_writeb(opaque, addr, value >> 8);
+ ppc4xx_i2c_writeb(opaque, addr + 1, value);
+}
+
+static uint32_t ppc4xx_i2c_readl (void *opaque, target_phys_addr_t addr)
+{
+ uint32_t ret;
+
+#ifdef DEBUG_I2C
+ printf("%s: addr " PADDRX "\n", __func__, addr);
+#endif
+ ret = ppc4xx_i2c_readb(opaque, addr) << 24;
+ ret |= ppc4xx_i2c_readb(opaque, addr + 1) << 16;
+ ret |= ppc4xx_i2c_readb(opaque, addr + 2) << 8;
+ ret |= ppc4xx_i2c_readb(opaque, addr + 3);
+
+ return ret;
+}
+
+static void ppc4xx_i2c_writel (void *opaque,
+ target_phys_addr_t addr, uint32_t value)
+{
+#ifdef DEBUG_I2C
+ printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value);
+#endif
+ ppc4xx_i2c_writeb(opaque, addr, value >> 24);
+ ppc4xx_i2c_writeb(opaque, addr + 1, value >> 16);
+ ppc4xx_i2c_writeb(opaque, addr + 2, value >> 8);
+ ppc4xx_i2c_writeb(opaque, addr + 3, value);
+}
+
+static CPUReadMemoryFunc *i2c_read[] = {
+ &ppc4xx_i2c_readb,
+ &ppc4xx_i2c_readw,
+ &ppc4xx_i2c_readl,
+};
+
+static CPUWriteMemoryFunc *i2c_write[] = {
+ &ppc4xx_i2c_writeb,
+ &ppc4xx_i2c_writew,
+ &ppc4xx_i2c_writel,
+};
+
+static void ppc4xx_i2c_reset (void *opaque)
+{
+ ppc4xx_i2c_t *i2c;
+
+ i2c = opaque;
+ i2c->mdata = 0x00;
+ i2c->sdata = 0x00;
+ i2c->cntl = 0x00;
+ i2c->mdcntl = 0x00;
+ i2c->sts = 0x00;
+ i2c->extsts = 0x00;
+ i2c->clkdiv = 0x00;
+ i2c->xfrcnt = 0x00;
+ i2c->directcntl = 0x0F;
+}
+
+void ppc405_i2c_init (CPUState *env, ppc4xx_mmio_t *mmio,
+ target_phys_addr_t offset, qemu_irq irq)
+{
+ ppc4xx_i2c_t *i2c;
+
+ i2c = qemu_mallocz(sizeof(ppc4xx_i2c_t));
+ if (i2c != NULL) {
+ i2c->base = offset;
+ i2c->irq = irq;
+ ppc4xx_i2c_reset(i2c);
+#ifdef DEBUG_I2C
+ printf("%s: offset=" PADDRX "\n", __func__, offset);
+#endif
+ ppc4xx_mmio_register(env, mmio, offset, 0x011,
+ i2c_read, i2c_write, i2c);
+ qemu_register_reset(ppc4xx_i2c_reset, i2c);
+ }
+}
+
+/*****************************************************************************/
+/* General purpose timers */
+typedef struct ppc4xx_gpt_t ppc4xx_gpt_t;
+struct ppc4xx_gpt_t {
+ target_phys_addr_t base;
+ int64_t tb_offset;
+ uint32_t tb_freq;
+ struct QEMUTimer *timer;
+ qemu_irq irqs[5];
+ uint32_t oe;
+ uint32_t ol;
+ uint32_t im;
+ uint32_t is;
+ uint32_t ie;
+ uint32_t comp[5];
+ uint32_t mask[5];
+};
+
+static uint32_t ppc4xx_gpt_readb (void *opaque, target_phys_addr_t addr)
+{
+#ifdef DEBUG_GPT
+ printf("%s: addr " PADDRX "\n", __func__, addr);
+#endif
+ /* XXX: generate a bus fault */
+ return -1;
+}
+
+static void ppc4xx_gpt_writeb (void *opaque,
+ target_phys_addr_t addr, uint32_t value)
+{
+#ifdef DEBUG_I2C
+ printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value);
+#endif
+ /* XXX: generate a bus fault */
+}
+
+static uint32_t ppc4xx_gpt_readw (void *opaque, target_phys_addr_t addr)
+{
+#ifdef DEBUG_GPT
+ printf("%s: addr " PADDRX "\n", __func__, addr);
+#endif
+ /* XXX: generate a bus fault */
+ return -1;
+}
+
+static void ppc4xx_gpt_writew (void *opaque,
+ target_phys_addr_t addr, uint32_t value)
+{
+#ifdef DEBUG_I2C
+ printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value);
+#endif
+ /* XXX: generate a bus fault */
+}
+
+static int ppc4xx_gpt_compare (ppc4xx_gpt_t *gpt, int n)
+{
+ /* XXX: TODO */
+ return 0;
+}
+
+static void ppc4xx_gpt_set_output (ppc4xx_gpt_t *gpt, int n, int level)
+{
+ /* XXX: TODO */
+}
+
+static void ppc4xx_gpt_set_outputs (ppc4xx_gpt_t *gpt)
+{
+ uint32_t mask;
+ int i;
+
+ mask = 0x80000000;
+ for (i = 0; i < 5; i++) {
+ if (gpt->oe & mask) {
+ /* Output is enabled */
+ if (ppc4xx_gpt_compare(gpt, i)) {
+ /* Comparison is OK */
+ ppc4xx_gpt_set_output(gpt, i, gpt->ol & mask);
+ } else {
+ /* Comparison is KO */
+ ppc4xx_gpt_set_output(gpt, i, gpt->ol & mask ? 0 : 1);
+ }
+ }
+ mask = mask >> 1;
+ }
+
+}
+
+static void ppc4xx_gpt_set_irqs (ppc4xx_gpt_t *gpt)
+{
+ uint32_t mask;
+ int i;
+
+ mask = 0x00008000;
+ for (i = 0; i < 5; i++) {
+ if (gpt->is & gpt->im & mask)
+ qemu_irq_raise(gpt->irqs[i]);
+ else
+ qemu_irq_lower(gpt->irqs[i]);
+ mask = mask >> 1;
+ }
+
+}
+
+static void ppc4xx_gpt_compute_timer (ppc4xx_gpt_t *gpt)
+{
+ /* XXX: TODO */
+}
+
+static uint32_t ppc4xx_gpt_readl (void *opaque, target_phys_addr_t addr)
+{
+ ppc4xx_gpt_t *gpt;
+ uint32_t ret;
+ int idx;
+
+#ifdef DEBUG_GPT
+ printf("%s: addr " PADDRX "\n", __func__, addr);
+#endif
+ gpt = opaque;
+ switch (addr - gpt->base) {
+ case 0x00:
+ /* Time base counter */
+ ret = muldiv64(qemu_get_clock(vm_clock) + gpt->tb_offset,
+ gpt->tb_freq, ticks_per_sec);
+ break;
+ case 0x10:
+ /* Output enable */
+ ret = gpt->oe;
+ break;
+ case 0x14:
+ /* Output level */
+ ret = gpt->ol;
+ break;
+ case 0x18:
+ /* Interrupt mask */
+ ret = gpt->im;
+ break;
+ case 0x1C:
+ case 0x20:
+ /* Interrupt status */
+ ret = gpt->is;
+ break;
+ case 0x24:
+ /* Interrupt enable */
+ ret = gpt->ie;
+ break;
+ case 0x80 ... 0x90:
+ /* Compare timer */
+ idx = ((addr - gpt->base) - 0x80) >> 2;
+ ret = gpt->comp[idx];
+ break;
+ case 0xC0 ... 0xD0:
+ /* Compare mask */
+ idx = ((addr - gpt->base) - 0xC0) >> 2;
+ ret = gpt->mask[idx];
+ break;
+ default:
+ ret = -1;
+ break;
+ }
+
+ return ret;
+}
+
+static void ppc4xx_gpt_writel (void *opaque,
+ target_phys_addr_t addr, uint32_t value)
+{
+ ppc4xx_gpt_t *gpt;
+ int idx;
+
+#ifdef DEBUG_I2C
+ printf("%s: addr " PADDRX " val %08x\n", __func__, addr, value);
+#endif
+ gpt = opaque;
+ switch (addr - gpt->base) {
+ case 0x00:
+ /* Time base counter */
+ gpt->tb_offset = muldiv64(value, ticks_per_sec, gpt->tb_freq)
+ - qemu_get_clock(vm_clock);
+ ppc4xx_gpt_compute_timer(gpt);
+ break;
+ case 0x10:
+ /* Output enable */
+ gpt->oe = value & 0xF8000000;
+ ppc4xx_gpt_set_outputs(gpt);
+ break;
+ case 0x14:
+ /* Output level */
+ gpt->ol = value & 0xF8000000;
+ ppc4xx_gpt_set_outputs(gpt);
+ break;
+ case 0x18:
+ /* Interrupt mask */
+ gpt->im = value & 0x0000F800;
+ break;
+ case 0x1C:
+ /* Interrupt status set */
+ gpt->is |= value & 0x0000F800;
+ ppc4xx_gpt_set_irqs(gpt);
+ break;
+ case 0x20:
+ /* Interrupt status clear */
+ gpt->is &= ~(value & 0x0000F800);
+ ppc4xx_gpt_set_irqs(gpt);
+ break;
+ case 0x24:
+ /* Interrupt enable */
+ gpt->ie = value & 0x0000F800;
+ ppc4xx_gpt_set_irqs(gpt);
+ break;
+ case 0x80 ... 0x90:
+ /* Compare timer */
+ idx = ((addr - gpt->base) - 0x80) >> 2;
+ gpt->comp[idx] = value & 0xF8000000;
+ ppc4xx_gpt_compute_timer(gpt);
+ break;
+ case 0xC0 ... 0xD0:
+ /* Compare mask */
+ idx = ((addr - gpt->base) - 0xC0) >> 2;
+ gpt->mask[idx] = value & 0xF8000000;
+ ppc4xx_gpt_compute_timer(gpt);
+ break;
+ }
+}
+
+static CPUReadMemoryFunc *gpt_read[] = {
+ &ppc4xx_gpt_readb,
+ &ppc4xx_gpt_readw,
+ &ppc4xx_gpt_readl,
+};
+
+static CPUWriteMemoryFunc *gpt_write[] = {
+ &ppc4xx_gpt_writeb,
+ &ppc4xx_gpt_writew,
+ &ppc4xx_gpt_writel,
+};
+
+static void ppc4xx_gpt_cb (void *opaque)
+{
+ ppc4xx_gpt_t *gpt;
+
+ gpt = opaque;
+ ppc4xx_gpt_set_irqs(gpt);
+ ppc4xx_gpt_set_outputs(gpt);
+ ppc4xx_gpt_compute_timer(gpt);
+}
+
+static void ppc4xx_gpt_reset (void *opaque)
+{
+ ppc4xx_gpt_t *gpt;
+ int i;
+
+ gpt = opaque;
+ qemu_del_timer(gpt->timer);
+ gpt->oe = 0x00000000;
+ gpt->ol = 0x00000000;
+ gpt->im = 0x00000000;
+ gpt->is = 0x00000000;
+ gpt->ie = 0x00000000;
+ for (i = 0; i < 5; i++) {
+ gpt->comp[i] = 0x00000000;
+ gpt->mask[i] = 0x00000000;
+ }
+}
+
+void ppc4xx_gpt_init (CPUState *env, ppc4xx_mmio_t *mmio,
+ target_phys_addr_t offset, qemu_irq irqs[5])
+{
+ ppc4xx_gpt_t *gpt;
+ int i;
+
+ gpt = qemu_mallocz(sizeof(ppc4xx_gpt_t));
+ if (gpt != NULL) {
+ gpt->base = offset;
+ for (i = 0; i < 5; i++)
+ gpt->irqs[i] = irqs[i];
+ gpt->timer = qemu_new_timer(vm_clock, &ppc4xx_gpt_cb, gpt);
+ ppc4xx_gpt_reset(gpt);
+#ifdef DEBUG_GPT
+ printf("%s: offset=" PADDRX "\n", __func__, offset);
+#endif
+ ppc4xx_mmio_register(env, mmio, offset, 0x0D4,
+ gpt_read, gpt_write, gpt);
+ qemu_register_reset(ppc4xx_gpt_reset, gpt);
+ }
+}
+
+/*****************************************************************************/
+/* MAL */
+enum {
+ MAL0_CFG = 0x180,
+ MAL0_ESR = 0x181,
+ MAL0_IER = 0x182,
+ MAL0_TXCASR = 0x184,
+ MAL0_TXCARR = 0x185,
+ MAL0_TXEOBISR = 0x186,
+ MAL0_TXDEIR = 0x187,
+ MAL0_RXCASR = 0x190,
+ MAL0_RXCARR = 0x191,
+ MAL0_RXEOBISR = 0x192,
+ MAL0_RXDEIR = 0x193,
+ MAL0_TXCTP0R = 0x1A0,
+ MAL0_TXCTP1R = 0x1A1,
+ MAL0_TXCTP2R = 0x1A2,
+ MAL0_TXCTP3R = 0x1A3,
+ MAL0_RXCTP0R = 0x1C0,
+ MAL0_RXCTP1R = 0x1C1,
+ MAL0_RCBS0 = 0x1E0,
+ MAL0_RCBS1 = 0x1E1,
+};
+
+typedef struct ppc40x_mal_t ppc40x_mal_t;
+struct ppc40x_mal_t {
+ qemu_irq irqs[4];
+ uint32_t cfg;
+ uint32_t esr;
+ uint32_t ier;
+ uint32_t txcasr;
+ uint32_t txcarr;
+ uint32_t txeobisr;
+ uint32_t txdeir;
+ uint32_t rxcasr;
+ uint32_t rxcarr;
+ uint32_t rxeobisr;
+ uint32_t rxdeir;
+ uint32_t txctpr[4];
+ uint32_t rxctpr[2];
+ uint32_t rcbs[2];
+};
+
+static void ppc40x_mal_reset (void *opaque);
+
+static target_ulong dcr_read_mal (void *opaque, int dcrn)
+{
+ ppc40x_mal_t *mal;
+ target_ulong ret;
+
+ mal = opaque;
+ switch (dcrn) {
+ case MAL0_CFG:
+ ret = mal->cfg;
+ break;
+ case MAL0_ESR:
+ ret = mal->esr;
+ break;
+ case MAL0_IER:
+ ret = mal->ier;
+ break;
+ case MAL0_TXCASR:
+ ret = mal->txcasr;
+ break;
+ case MAL0_TXCARR:
+ ret = mal->txcarr;
+ break;
+ case MAL0_TXEOBISR:
+ ret = mal->txeobisr;
+ break;
+ case MAL0_TXDEIR:
+ ret = mal->txdeir;
+ break;
+ case MAL0_RXCASR:
+ ret = mal->rxcasr;
+ break;
+ case MAL0_RXCARR:
+ ret = mal->rxcarr;
+ break;
+ case MAL0_RXEOBISR:
+ ret = mal->rxeobisr;
+ break;
+ case MAL0_RXDEIR:
+ ret = mal->rxdeir;
+ break;
+ case MAL0_TXCTP0R:
+ ret = mal->txctpr[0];
+ break;
+ case MAL0_TXCTP1R:
+ ret = mal->txctpr[1];
+ break;
+ case MAL0_TXCTP2R:
+ ret = mal->txctpr[2];
+ break;
+ case MAL0_TXCTP3R:
+ ret = mal->txctpr[3];
+ break;
+ case MAL0_RXCTP0R:
+ ret = mal->rxctpr[0];
+ break;
+ case MAL0_RXCTP1R:
+ ret = mal->rxctpr[1];
+ break;
+ case MAL0_RCBS0:
+ ret = mal->rcbs[0];
+ break;
+ case MAL0_RCBS1:
+ ret = mal->rcbs[1];
+ break;
+ default:
+ ret = 0;
+ break;
+ }
+
+ return ret;
+}
+
+static void dcr_write_mal (void *opaque, int dcrn, target_ulong val)
+{
+ ppc40x_mal_t *mal;
+ int idx;
+
+ mal = opaque;
+ switch (dcrn) {
+ case MAL0_CFG:
+ if (val & 0x80000000)
+ ppc40x_mal_reset(mal);
+ mal->cfg = val & 0x00FFC087;
+ break;
+ case MAL0_ESR:
+ /* Read/clear */
+ mal->esr &= ~val;
+ break;
+ case MAL0_IER:
+ mal->ier = val & 0x0000001F;
+ break;
+ case MAL0_TXCASR:
+ mal->txcasr = val & 0xF0000000;
+ break;
+ case MAL0_TXCARR:
+ mal->txcarr = val & 0xF0000000;
+ break;
+ case MAL0_TXEOBISR:
+ /* Read/clear */
+ mal->txeobisr &= ~val;
+ break;
+ case MAL0_TXDEIR:
+ /* Read/clear */
+ mal->txdeir &= ~val;
+ break;
+ case MAL0_RXCASR:
+ mal->rxcasr = val & 0xC0000000;
+ break;
+ case MAL0_RXCARR:
+ mal->rxcarr = val & 0xC0000000;
+ break;
+ case MAL0_RXEOBISR:
+ /* Read/clear */
+ mal->rxeobisr &= ~val;
+ break;
+ case MAL0_RXDEIR:
+ /* Read/clear */
+ mal->rxdeir &= ~val;
+ break;
+ case MAL0_TXCTP0R:
+ idx = 0;
+ goto update_tx_ptr;
+ case MAL0_TXCTP1R:
+ idx = 1;
+ goto update_tx_ptr;
+ case MAL0_TXCTP2R:
+ idx = 2;
+ goto update_tx_ptr;
+ case MAL0_TXCTP3R:
+ idx = 3;
+ update_tx_ptr:
+ mal->txctpr[idx] = val;
+ break;
+ case MAL0_RXCTP0R:
+ idx = 0;
+ goto update_rx_ptr;
+ case MAL0_RXCTP1R:
+ idx = 1;
+ update_rx_ptr:
+ mal->rxctpr[idx] = val;
+ break;
+ case MAL0_RCBS0:
+ idx = 0;
+ goto update_rx_size;
+ case MAL0_RCBS1:
+ idx = 1;
+ update_rx_size:
+ mal->rcbs[idx] = val & 0x000000FF;
+ break;
+ }
+}
+
+static void ppc40x_mal_reset (void *opaque)
+{
+ ppc40x_mal_t *mal;
+
+ mal = opaque;
+ mal->cfg = 0x0007C000;
+ mal->esr = 0x00000000;
+ mal->ier = 0x00000000;
+ mal->rxcasr = 0x00000000;
+ mal->rxdeir = 0x00000000;
+ mal->rxeobisr = 0x00000000;
+ mal->txcasr = 0x00000000;
+ mal->txdeir = 0x00000000;
+ mal->txeobisr = 0x00000000;
+}
+
+void ppc405_mal_init (CPUState *env, qemu_irq irqs[4])
+{
+ ppc40x_mal_t *mal;
+ int i;
+
+ mal = qemu_mallocz(sizeof(ppc40x_mal_t));
+ if (mal != NULL) {
+ for (i = 0; i < 4; i++)
+ mal->irqs[i] = irqs[i];
+ ppc40x_mal_reset(mal);
+ qemu_register_reset(&ppc40x_mal_reset, mal);
+ ppc_dcr_register(env, MAL0_CFG,
+ mal, &dcr_read_mal, &dcr_write_mal);
+ ppc_dcr_register(env, MAL0_ESR,
+ mal, &dcr_read_mal, &dcr_write_mal);
+ ppc_dcr_register(env, MAL0_IER,
+ mal, &dcr_read_mal, &dcr_write_mal);
+ ppc_dcr_register(env, MAL0_TXCASR,
+ mal, &dcr_read_mal, &dcr_write_mal);
+ ppc_dcr_register(env, MAL0_TXCARR,
+ mal, &dcr_read_mal, &dcr_write_mal);
+ ppc_dcr_register(env, MAL0_TXEOBISR,
+ mal, &dcr_read_mal, &dcr_write_mal);
+ ppc_dcr_register(env, MAL0_TXDEIR,
+ mal, &dcr_read_mal, &dcr_write_mal);
+ ppc_dcr_register(env, MAL0_RXCASR,
+ mal, &dcr_read_mal, &dcr_write_mal);
+ ppc_dcr_register(env, MAL0_RXCARR,
+ mal, &dcr_read_mal, &dcr_write_mal);
+ ppc_dcr_register(env, MAL0_RXEOBISR,
+ mal, &dcr_read_mal, &dcr_write_mal);
+ ppc_dcr_register(env, MAL0_RXDEIR,
+ mal, &dcr_read_mal, &dcr_write_mal);
+ ppc_dcr_register(env, MAL0_TXCTP0R,
+ mal, &dcr_read_mal, &dcr_write_mal);
+ ppc_dcr_register(env, MAL0_TXCTP1R,
+ mal, &dcr_read_mal, &dcr_write_mal);
+ ppc_dcr_register(env, MAL0_TXCTP2R,
+ mal, &dcr_read_mal, &dcr_write_mal);
+ ppc_dcr_register(env, MAL0_TXCTP3R,
+ mal, &dcr_read_mal, &dcr_write_mal);
+ ppc_dcr_register(env, MAL0_RXCTP0R,
+ mal, &dcr_read_mal, &dcr_write_mal);
+ ppc_dcr_register(env, MAL0_RXCTP1R,
+ mal, &dcr_read_mal, &dcr_write_mal);
+ ppc_dcr_register(env, MAL0_RCBS0,
+ mal, &dcr_read_mal, &dcr_write_mal);
+ ppc_dcr_register(env, MAL0_RCBS1,
+ mal, &dcr_read_mal, &dcr_write_mal);
+ }
+}
+
+/*****************************************************************************/
+/* SPR */
+void ppc40x_core_reset (CPUState *env)
+{
+ target_ulong dbsr;
+
+ printf("Reset PowerPC core\n");
+ cpu_ppc_reset(env);
+ dbsr = env->spr[SPR_40x_DBSR];
+ dbsr &= ~0x00000300;
+ dbsr |= 0x00000100;
+ env->spr[SPR_40x_DBSR] = dbsr;
+ cpu_loop_exit();
+}
+
+void ppc40x_chip_reset (CPUState *env)
+{
+ target_ulong dbsr;
+
+ printf("Reset PowerPC chip\n");
+ cpu_ppc_reset(env);
+ /* XXX: TODO reset all internal peripherals */
+ dbsr = env->spr[SPR_40x_DBSR];
+ dbsr &= ~0x00000300;
+ dbsr |= 0x00000200;
+ env->spr[SPR_40x_DBSR] = dbsr;
+ cpu_loop_exit();
+}
+
+void ppc40x_system_reset (CPUState *env)
+{
+ printf("Reset PowerPC system\n");
+ qemu_system_reset_request();
+}
+
+void store_40x_dbcr0 (CPUState *env, uint32_t val)
+{
+ switch ((val >> 28) & 0x3) {
+ case 0x0:
+ /* No action */
+ break;
+ case 0x1:
+ /* Core reset */
+ ppc40x_core_reset(env);
+ break;
+ case 0x2:
+ /* Chip reset */
+ ppc40x_chip_reset(env);
+ break;
+ case 0x3:
+ /* System reset */
+ ppc40x_system_reset(env);
+ break;
+ }
+}
+
+/*****************************************************************************/
+/* PowerPC 405CR */
+enum {
+ PPC405CR_CPC0_PLLMR = 0x0B0,
+ PPC405CR_CPC0_CR0 = 0x0B1,
+ PPC405CR_CPC0_CR1 = 0x0B2,
+ PPC405CR_CPC0_PSR = 0x0B4,
+ PPC405CR_CPC0_JTAGID = 0x0B5,
+ PPC405CR_CPC0_ER = 0x0B9,
+ PPC405CR_CPC0_FR = 0x0BA,
+ PPC405CR_CPC0_SR = 0x0BB,
+};
+
+enum {
+ PPC405CR_CPU_CLK = 0,
+ PPC405CR_TMR_CLK = 1,
+ PPC405CR_PLB_CLK = 2,
+ PPC405CR_SDRAM_CLK = 3,
+ PPC405CR_OPB_CLK = 4,
+ PPC405CR_EXT_CLK = 5,
+ PPC405CR_UART_CLK = 6,
+ PPC405CR_CLK_NB = 7,
+};
+
+typedef struct ppc405cr_cpc_t ppc405cr_cpc_t;
+struct ppc405cr_cpc_t {
+ clk_setup_t clk_setup[PPC405CR_CLK_NB];
+ uint32_t sysclk;
+ uint32_t psr;
+ uint32_t cr0;
+ uint32_t cr1;
+ uint32_t jtagid;
+ uint32_t pllmr;
+ uint32_t er;
+ uint32_t fr;
+};
+
+static void ppc405cr_clk_setup (ppc405cr_cpc_t *cpc)
+{
+ uint64_t VCO_out, PLL_out;
+ uint32_t CPU_clk, TMR_clk, SDRAM_clk, PLB_clk, OPB_clk, EXT_clk, UART_clk;
+ int M, D0, D1, D2;
+
+ D0 = ((cpc->pllmr >> 26) & 0x3) + 1; /* CBDV */
+ if (cpc->pllmr & 0x80000000) {
+ D1 = (((cpc->pllmr >> 20) - 1) & 0xF) + 1; /* FBDV */
+ D2 = 8 - ((cpc->pllmr >> 16) & 0x7); /* FWDVA */
+ M = D0 * D1 * D2;
+ VCO_out = cpc->sysclk * M;
+ if (VCO_out < 400000000 || VCO_out > 800000000) {
+ /* PLL cannot lock */
+ cpc->pllmr &= ~0x80000000;
+ goto bypass_pll;
+ }
+ PLL_out = VCO_out / D2;
+ } else {
+ /* Bypass PLL */
+ bypass_pll:
+ M = D0;
+ PLL_out = cpc->sysclk * M;
+ }
+ CPU_clk = PLL_out;
+ if (cpc->cr1 & 0x00800000)
+ TMR_clk = cpc->sysclk; /* Should have a separate clock */
+ else
+ TMR_clk = CPU_clk;
+ PLB_clk = CPU_clk / D0;
+ SDRAM_clk = PLB_clk;
+ D0 = ((cpc->pllmr >> 10) & 0x3) + 1;
+ OPB_clk = PLB_clk / D0;
+ D0 = ((cpc->pllmr >> 24) & 0x3) + 2;
+ EXT_clk = PLB_clk / D0;
+ D0 = ((cpc->cr0 >> 1) & 0x1F) + 1;
+ UART_clk = CPU_clk / D0;
+ /* Setup CPU clocks */
+ clk_setup(&cpc->clk_setup[PPC405CR_CPU_CLK], CPU_clk);
+ /* Setup time-base clock */
+ clk_setup(&cpc->clk_setup[PPC405CR_TMR_CLK], TMR_clk);
+ /* Setup PLB clock */
+ clk_setup(&cpc->clk_setup[PPC405CR_PLB_CLK], PLB_clk);
+ /* Setup SDRAM clock */
+ clk_setup(&cpc->clk_setup[PPC405CR_SDRAM_CLK], SDRAM_clk);
+ /* Setup OPB clock */
+ clk_setup(&cpc->clk_setup[PPC405CR_OPB_CLK], OPB_clk);
+ /* Setup external clock */
+ clk_setup(&cpc->clk_setup[PPC405CR_EXT_CLK], EXT_clk);
+ /* Setup UART clock */
+ clk_setup(&cpc->clk_setup[PPC405CR_UART_CLK], UART_clk);
+}
+
+static target_ulong dcr_read_crcpc (void *opaque, int dcrn)
+{
+ ppc405cr_cpc_t *cpc;
+ target_ulong ret;
+
+ cpc = opaque;
+ switch (dcrn) {
+ case PPC405CR_CPC0_PLLMR:
+ ret = cpc->pllmr;
+ break;
+ case PPC405CR_CPC0_CR0:
+ ret = cpc->cr0;
+ break;
+ case PPC405CR_CPC0_CR1:
+ ret = cpc->cr1;
+ break;
+ case PPC405CR_CPC0_PSR:
+ ret = cpc->psr;
+ break;
+ case PPC405CR_CPC0_JTAGID:
+ ret = cpc->jtagid;
+ break;
+ case PPC405CR_CPC0_ER:
+ ret = cpc->er;
+ break;
+ case PPC405CR_CPC0_FR:
+ ret = cpc->fr;
+ break;
+ case PPC405CR_CPC0_SR:
+ ret = ~(cpc->er | cpc->fr) & 0xFFFF0000;
+ break;
+ default:
+ /* Avoid gcc warning */
+ ret = 0;
+ break;
+ }
+
+ return ret;
+}
+
+static void dcr_write_crcpc (void *opaque, int dcrn, target_ulong val)
+{
+ ppc405cr_cpc_t *cpc;
+
+ cpc = opaque;
+ switch (dcrn) {
+ case PPC405CR_CPC0_PLLMR:
+ cpc->pllmr = val & 0xFFF77C3F;
+ break;
+ case PPC405CR_CPC0_CR0:
+ cpc->cr0 = val & 0x0FFFFFFE;
+ break;
+ case PPC405CR_CPC0_CR1:
+ cpc->cr1 = val & 0x00800000;
+ break;
+ case PPC405CR_CPC0_PSR:
+ /* Read-only */
+ break;
+ case PPC405CR_CPC0_JTAGID:
+ /* Read-only */
+ break;
+ case PPC405CR_CPC0_ER:
+ cpc->er = val & 0xBFFC0000;
+ break;
+ case PPC405CR_CPC0_FR:
+ cpc->fr = val & 0xBFFC0000;
+ break;
+ case PPC405CR_CPC0_SR:
+ /* Read-only */
+ break;
+ }
+}
+
+static void ppc405cr_cpc_reset (void *opaque)
+{
+ ppc405cr_cpc_t *cpc;
+ int D;
+
+ cpc = opaque;
+ /* Compute PLLMR value from PSR settings */
+ cpc->pllmr = 0x80000000;
+ /* PFWD */
+ switch ((cpc->psr >> 30) & 3) {
+ case 0:
+ /* Bypass */
+ cpc->pllmr &= ~0x80000000;
+ break;
+ case 1:
+ /* Divide by 3 */
+ cpc->pllmr |= 5 << 16;
+ break;
+ case 2:
+ /* Divide by 4 */
+ cpc->pllmr |= 4 << 16;
+ break;
+ case 3:
+ /* Divide by 6 */
+ cpc->pllmr |= 2 << 16;
+ break;
+ }
+ /* PFBD */
+ D = (cpc->psr >> 28) & 3;
+ cpc->pllmr |= (D + 1) << 20;
+ /* PT */
+ D = (cpc->psr >> 25) & 7;
+ switch (D) {
+ case 0x2:
+ cpc->pllmr |= 0x13;
+ break;
+ case 0x4:
+ cpc->pllmr |= 0x15;
+ break;
+ case 0x5:
+ cpc->pllmr |= 0x16;
+ break;
+ default:
+ break;
+ }
+ /* PDC */
+ D = (cpc->psr >> 23) & 3;
+ cpc->pllmr |= D << 26;
+ /* ODP */
+ D = (cpc->psr >> 21) & 3;
+ cpc->pllmr |= D << 10;
+ /* EBPD */
+ D = (cpc->psr >> 17) & 3;
+ cpc->pllmr |= D << 24;
+ cpc->cr0 = 0x0000003C;
+ cpc->cr1 = 0x2B0D8800;
+ cpc->er = 0x00000000;
+ cpc->fr = 0x00000000;
+ ppc405cr_clk_setup(cpc);
+}
+
+static void ppc405cr_clk_init (ppc405cr_cpc_t *cpc)
+{
+ int D;
+
+ /* XXX: this should be read from IO pins */
+ cpc->psr = 0x00000000; /* 8 bits ROM */
+ /* PFWD */
+ D = 0x2; /* Divide by 4 */
+ cpc->psr |= D << 30;
+ /* PFBD */
+ D = 0x1; /* Divide by 2 */
+ cpc->psr |= D << 28;
+ /* PDC */
+ D = 0x1; /* Divide by 2 */
+ cpc->psr |= D << 23;
+ /* PT */
+ D = 0x5; /* M = 16 */
+ cpc->psr |= D << 25;
+ /* ODP */
+ D = 0x1; /* Divide by 2 */
+ cpc->psr |= D << 21;
+ /* EBDP */
+ D = 0x2; /* Divide by 4 */
+ cpc->psr |= D << 17;
+}
+
+static void ppc405cr_cpc_init (CPUState *env, clk_setup_t clk_setup[7],
+ uint32_t sysclk)
+{
+ ppc405cr_cpc_t *cpc;
+
+ cpc = qemu_mallocz(sizeof(ppc405cr_cpc_t));
+ if (cpc != NULL) {
+ memcpy(cpc->clk_setup, clk_setup,
+ PPC405CR_CLK_NB * sizeof(clk_setup_t));
+ cpc->sysclk = sysclk;
+ cpc->jtagid = 0x42051049;
+ ppc_dcr_register(env, PPC405CR_CPC0_PSR, cpc,
+ &dcr_read_crcpc, &dcr_write_crcpc);
+ ppc_dcr_register(env, PPC405CR_CPC0_CR0, cpc,
+ &dcr_read_crcpc, &dcr_write_crcpc);
+ ppc_dcr_register(env, PPC405CR_CPC0_CR1, cpc,
+ &dcr_read_crcpc, &dcr_write_crcpc);
+ ppc_dcr_register(env, PPC405CR_CPC0_JTAGID, cpc,
+ &dcr_read_crcpc, &dcr_write_crcpc);
+ ppc_dcr_register(env, PPC405CR_CPC0_PLLMR, cpc,
+ &dcr_read_crcpc, &dcr_write_crcpc);
+ ppc_dcr_register(env, PPC405CR_CPC0_ER, cpc,
+ &dcr_read_crcpc, &dcr_write_crcpc);
+ ppc_dcr_register(env, PPC405CR_CPC0_FR, cpc,
+ &dcr_read_crcpc, &dcr_write_crcpc);
+ ppc_dcr_register(env, PPC405CR_CPC0_SR, cpc,
+ &dcr_read_crcpc, &dcr_write_crcpc);
+ ppc405cr_clk_init(cpc);
+ qemu_register_reset(ppc405cr_cpc_reset, cpc);
+ ppc405cr_cpc_reset(cpc);
+ }
+}
+
+CPUState *ppc405cr_init (target_ulong ram_bases[4], target_ulong ram_sizes[4],
+ uint32_t sysclk, qemu_irq **picp,
+ ram_addr_t *offsetp, int do_init)
+{
+ clk_setup_t clk_setup[PPC405CR_CLK_NB];
+ qemu_irq dma_irqs[4];
+ CPUState *env;
+ ppc4xx_mmio_t *mmio;
+ qemu_irq *pic, *irqs;
+ ram_addr_t offset;
+ int i;
+
+ memset(clk_setup, 0, sizeof(clk_setup));
+ env = ppc405_init("405cr", &clk_setup[PPC405CR_CPU_CLK],
+ &clk_setup[PPC405CR_TMR_CLK], sysclk);
+ /* Memory mapped devices registers */
+ mmio = ppc4xx_mmio_init(env, 0xEF600000);
+ /* PLB arbitrer */
+ ppc4xx_plb_init(env);
+ /* PLB to OPB bridge */
+ ppc4xx_pob_init(env);
+ /* OBP arbitrer */
+ ppc4xx_opba_init(env, mmio, 0x600);
+ /* Universal interrupt controller */
+ irqs = qemu_mallocz(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB);
+ irqs[PPCUIC_OUTPUT_INT] =
+ ((qemu_irq *)env->irq_inputs)[PPC405_INPUT_INT];
+ irqs[PPCUIC_OUTPUT_CINT] =
+ ((qemu_irq *)env->irq_inputs)[PPC405_INPUT_CINT];
+ pic = ppcuic_init(env, irqs, 0x0C0, 0, 1);
+ *picp = pic;
+ /* SDRAM controller */
+ ppc405_sdram_init(env, pic[14], 1, ram_bases, ram_sizes, do_init);
+ offset = 0;
+ for (i = 0; i < 4; i++)
+ offset += ram_sizes[i];
+ /* External bus controller */
+ ppc405_ebc_init(env);
+ /* DMA controller */
+ dma_irqs[0] = pic[26];
+ dma_irqs[1] = pic[25];
+ dma_irqs[2] = pic[24];
+ dma_irqs[3] = pic[23];
+ ppc405_dma_init(env, dma_irqs);
+ /* Serial ports */
+ if (serial_hds[0] != NULL) {
+ ppc405_serial_init(env, mmio, 0x300, pic[31], serial_hds[0]);
+ }
+ if (serial_hds[1] != NULL) {
+ ppc405_serial_init(env, mmio, 0x400, pic[30], serial_hds[1]);
+ }
+ /* IIC controller */
+ ppc405_i2c_init(env, mmio, 0x500, pic[29]);
+ /* GPIO */
+ ppc405_gpio_init(env, mmio, 0x700);
+ /* CPU control */
+ ppc405cr_cpc_init(env, clk_setup, sysclk);
+ *offsetp = offset;
+
+ return env;
+}
+
+/*****************************************************************************/
+/* PowerPC 405EP */
+/* CPU control */
+enum {
+ PPC405EP_CPC0_PLLMR0 = 0x0F0,
+ PPC405EP_CPC0_BOOT = 0x0F1,
+ PPC405EP_CPC0_EPCTL = 0x0F3,
+ PPC405EP_CPC0_PLLMR1 = 0x0F4,
+ PPC405EP_CPC0_UCR = 0x0F5,
+ PPC405EP_CPC0_SRR = 0x0F6,
+ PPC405EP_CPC0_JTAGID = 0x0F7,
+ PPC405EP_CPC0_PCI = 0x0F9,
+#if 0
+ PPC405EP_CPC0_ER = xxx,
+ PPC405EP_CPC0_FR = xxx,
+ PPC405EP_CPC0_SR = xxx,
+#endif
+};
+
+enum {
+ PPC405EP_CPU_CLK = 0,
+ PPC405EP_PLB_CLK = 1,
+ PPC405EP_OPB_CLK = 2,
+ PPC405EP_EBC_CLK = 3,
+ PPC405EP_MAL_CLK = 4,
+ PPC405EP_PCI_CLK = 5,
+ PPC405EP_UART0_CLK = 6,
+ PPC405EP_UART1_CLK = 7,
+ PPC405EP_CLK_NB = 8,
+};
+
+typedef struct ppc405ep_cpc_t ppc405ep_cpc_t;
+struct ppc405ep_cpc_t {
+ uint32_t sysclk;
+ clk_setup_t clk_setup[PPC405EP_CLK_NB];
+ uint32_t boot;
+ uint32_t epctl;
+ uint32_t pllmr[2];
+ uint32_t ucr;
+ uint32_t srr;
+ uint32_t jtagid;
+ uint32_t pci;
+ /* Clock and power management */
+ uint32_t er;
+ uint32_t fr;
+ uint32_t sr;
+};
+
+static void ppc405ep_compute_clocks (ppc405ep_cpc_t *cpc)
+{
+ uint32_t CPU_clk, PLB_clk, OPB_clk, EBC_clk, MAL_clk, PCI_clk;
+ uint32_t UART0_clk, UART1_clk;
+ uint64_t VCO_out, PLL_out;
+ int M, D;
+
+ VCO_out = 0;
+ if ((cpc->pllmr[1] & 0x80000000) && !(cpc->pllmr[1] & 0x40000000)) {
+ M = (((cpc->pllmr[1] >> 20) - 1) & 0xF) + 1; /* FBMUL */
+ // printf("FBMUL %01x %d\n", (cpc->pllmr[1] >> 20) & 0xF, M);
+ D = 8 - ((cpc->pllmr[1] >> 16) & 0x7); /* FWDA */
+ // printf("FWDA %01x %d\n", (cpc->pllmr[1] >> 16) & 0x7, D);
+ VCO_out = cpc->sysclk * M * D;
+ if (VCO_out < 500000000UL || VCO_out > 1000000000UL) {
+ /* Error - unlock the PLL */
+ printf("VCO out of range %" PRIu64 "\n", VCO_out);
+#if 0
+ cpc->pllmr[1] &= ~0x80000000;
+ goto pll_bypass;
+#endif
+ }
+ PLL_out = VCO_out / D;
+ /* Pretend the PLL is locked */
+ cpc->boot |= 0x00000001;
+ } else {
+#if 0
+ pll_bypass:
+#endif
+ PLL_out = cpc->sysclk;
+ if (cpc->pllmr[1] & 0x40000000) {
+ /* Pretend the PLL is not locked */
+ cpc->boot &= ~0x00000001;
+ }
+ }
+ /* Now, compute all other clocks */
+ D = ((cpc->pllmr[0] >> 20) & 0x3) + 1; /* CCDV */
+#ifdef DEBUG_CLOCKS
+ // printf("CCDV %01x %d\n", (cpc->pllmr[0] >> 20) & 0x3, D);
+#endif
+ CPU_clk = PLL_out / D;
+ D = ((cpc->pllmr[0] >> 16) & 0x3) + 1; /* CBDV */
+#ifdef DEBUG_CLOCKS
+ // printf("CBDV %01x %d\n", (cpc->pllmr[0] >> 16) & 0x3, D);
+#endif
+ PLB_clk = CPU_clk / D;
+ D = ((cpc->pllmr[0] >> 12) & 0x3) + 1; /* OPDV */
+#ifdef DEBUG_CLOCKS
+ // printf("OPDV %01x %d\n", (cpc->pllmr[0] >> 12) & 0x3, D);
+#endif
+ OPB_clk = PLB_clk / D;
+ D = ((cpc->pllmr[0] >> 8) & 0x3) + 2; /* EPDV */
+#ifdef DEBUG_CLOCKS
+ // printf("EPDV %01x %d\n", (cpc->pllmr[0] >> 8) & 0x3, D);
+#endif
+ EBC_clk = PLB_clk / D;
+ D = ((cpc->pllmr[0] >> 4) & 0x3) + 1; /* MPDV */
+#ifdef DEBUG_CLOCKS
+ // printf("MPDV %01x %d\n", (cpc->pllmr[0] >> 4) & 0x3, D);
+#endif
+ MAL_clk = PLB_clk / D;
+ D = (cpc->pllmr[0] & 0x3) + 1; /* PPDV */
+#ifdef DEBUG_CLOCKS
+ // printf("PPDV %01x %d\n", cpc->pllmr[0] & 0x3, D);
+#endif
+ PCI_clk = PLB_clk / D;
+ D = ((cpc->ucr - 1) & 0x7F) + 1; /* U0DIV */
+#ifdef DEBUG_CLOCKS
+ // printf("U0DIV %01x %d\n", cpc->ucr & 0x7F, D);
+#endif
+ UART0_clk = PLL_out / D;
+ D = (((cpc->ucr >> 8) - 1) & 0x7F) + 1; /* U1DIV */
+#ifdef DEBUG_CLOCKS
+ // printf("U1DIV %01x %d\n", (cpc->ucr >> 8) & 0x7F, D);
+#endif
+ UART1_clk = PLL_out / D;
+#ifdef DEBUG_CLOCKS
+ printf("Setup PPC405EP clocks - sysclk %d VCO %" PRIu64
+ " PLL out %" PRIu64 " Hz\n", cpc->sysclk, VCO_out, PLL_out);
+ printf("CPU %d PLB %d OPB %d EBC %d MAL %d PCI %d UART0 %d UART1 %d\n",
+ CPU_clk, PLB_clk, OPB_clk, EBC_clk, MAL_clk, PCI_clk,
+ UART0_clk, UART1_clk);
+ printf("CB %p opaque %p\n", cpc->clk_setup[PPC405EP_CPU_CLK].cb,
+ cpc->clk_setup[PPC405EP_CPU_CLK].opaque);
+#endif
+ /* Setup CPU clocks */
+ clk_setup(&cpc->clk_setup[PPC405EP_CPU_CLK], CPU_clk);
+ /* Setup PLB clock */
+ clk_setup(&cpc->clk_setup[PPC405EP_PLB_CLK], PLB_clk);
+ /* Setup OPB clock */
+ clk_setup(&cpc->clk_setup[PPC405EP_OPB_CLK], OPB_clk);
+ /* Setup external clock */
+ clk_setup(&cpc->clk_setup[PPC405EP_EBC_CLK], EBC_clk);
+ /* Setup MAL clock */
+ clk_setup(&cpc->clk_setup[PPC405EP_MAL_CLK], MAL_clk);
+ /* Setup PCI clock */
+ clk_setup(&cpc->clk_setup[PPC405EP_PCI_CLK], PCI_clk);
+ /* Setup UART0 clock */
+ clk_setup(&cpc->clk_setup[PPC405EP_UART0_CLK], UART0_clk);
+ /* Setup UART1 clock */
+ clk_setup(&cpc->clk_setup[PPC405EP_UART1_CLK], UART1_clk);
+}
+
+static target_ulong dcr_read_epcpc (void *opaque, int dcrn)
+{
+ ppc405ep_cpc_t *cpc;
+ target_ulong ret;
+
+ cpc = opaque;
+ switch (dcrn) {
+ case PPC405EP_CPC0_BOOT:
+ ret = cpc->boot;
+ break;
+ case PPC405EP_CPC0_EPCTL:
+ ret = cpc->epctl;
+ break;
+ case PPC405EP_CPC0_PLLMR0:
+ ret = cpc->pllmr[0];
+ break;
+ case PPC405EP_CPC0_PLLMR1:
+ ret = cpc->pllmr[1];
+ break;
+ case PPC405EP_CPC0_UCR:
+ ret = cpc->ucr;
+ break;
+ case PPC405EP_CPC0_SRR:
+ ret = cpc->srr;
+ break;
+ case PPC405EP_CPC0_JTAGID:
+ ret = cpc->jtagid;
+ break;
+ case PPC405EP_CPC0_PCI:
+ ret = cpc->pci;
+ break;
+ default:
+ /* Avoid gcc warning */
+ ret = 0;
+ break;
+ }
+
+ return ret;
+}
+
+static void dcr_write_epcpc (void *opaque, int dcrn, target_ulong val)
+{
+ ppc405ep_cpc_t *cpc;
+
+ cpc = opaque;
+ switch (dcrn) {
+ case PPC405EP_CPC0_BOOT:
+ /* Read-only register */
+ break;
+ case PPC405EP_CPC0_EPCTL:
+ /* Don't care for now */
+ cpc->epctl = val & 0xC00000F3;
+ break;
+ case PPC405EP_CPC0_PLLMR0:
+ cpc->pllmr[0] = val & 0x00633333;
+ ppc405ep_compute_clocks(cpc);
+ break;
+ case PPC405EP_CPC0_PLLMR1:
+ cpc->pllmr[1] = val & 0xC0F73FFF;
+ ppc405ep_compute_clocks(cpc);
+ break;
+ case PPC405EP_CPC0_UCR:
+ /* UART control - don't care for now */
+ cpc->ucr = val & 0x003F7F7F;
+ break;
+ case PPC405EP_CPC0_SRR:
+ cpc->srr = val;
+ break;
+ case PPC405EP_CPC0_JTAGID:
+ /* Read-only */
+ break;
+ case PPC405EP_CPC0_PCI:
+ cpc->pci = val;
+ break;
+ }
+}
+
+static void ppc405ep_cpc_reset (void *opaque)
+{
+ ppc405ep_cpc_t *cpc = opaque;
+
+ cpc->boot = 0x00000010; /* Boot from PCI - IIC EEPROM disabled */
+ cpc->epctl = 0x00000000;
+ cpc->pllmr[0] = 0x00011010;
+ cpc->pllmr[1] = 0x40000000;
+ cpc->ucr = 0x00000000;
+ cpc->srr = 0x00040000;
+ cpc->pci = 0x00000000;
+ cpc->er = 0x00000000;
+ cpc->fr = 0x00000000;
+ cpc->sr = 0x00000000;
+ ppc405ep_compute_clocks(cpc);
+}
+
+/* XXX: sysclk should be between 25 and 100 MHz */
+static void ppc405ep_cpc_init (CPUState *env, clk_setup_t clk_setup[8],
+ uint32_t sysclk)
+{
+ ppc405ep_cpc_t *cpc;
+
+ cpc = qemu_mallocz(sizeof(ppc405ep_cpc_t));
+ if (cpc != NULL) {
+ memcpy(cpc->clk_setup, clk_setup,
+ PPC405EP_CLK_NB * sizeof(clk_setup_t));
+ cpc->jtagid = 0x20267049;
+ cpc->sysclk = sysclk;
+ ppc405ep_cpc_reset(cpc);
+ qemu_register_reset(&ppc405ep_cpc_reset, cpc);
+ ppc_dcr_register(env, PPC405EP_CPC0_BOOT, cpc,
+ &dcr_read_epcpc, &dcr_write_epcpc);
+ ppc_dcr_register(env, PPC405EP_CPC0_EPCTL, cpc,
+ &dcr_read_epcpc, &dcr_write_epcpc);
+ ppc_dcr_register(env, PPC405EP_CPC0_PLLMR0, cpc,
+ &dcr_read_epcpc, &dcr_write_epcpc);
+ ppc_dcr_register(env, PPC405EP_CPC0_PLLMR1, cpc,
+ &dcr_read_epcpc, &dcr_write_epcpc);
+ ppc_dcr_register(env, PPC405EP_CPC0_UCR, cpc,
+ &dcr_read_epcpc, &dcr_write_epcpc);
+ ppc_dcr_register(env, PPC405EP_CPC0_SRR, cpc,
+ &dcr_read_epcpc, &dcr_write_epcpc);
+ ppc_dcr_register(env, PPC405EP_CPC0_JTAGID, cpc,
+ &dcr_read_epcpc, &dcr_write_epcpc);
+ ppc_dcr_register(env, PPC405EP_CPC0_PCI, cpc,
+ &dcr_read_epcpc, &dcr_write_epcpc);
+#if 0
+ ppc_dcr_register(env, PPC405EP_CPC0_ER, cpc,
+ &dcr_read_epcpc, &dcr_write_epcpc);
+ ppc_dcr_register(env, PPC405EP_CPC0_FR, cpc,
+ &dcr_read_epcpc, &dcr_write_epcpc);
+ ppc_dcr_register(env, PPC405EP_CPC0_SR, cpc,
+ &dcr_read_epcpc, &dcr_write_epcpc);
+#endif
+ }
+}
+
+CPUState *ppc405ep_init (target_ulong ram_bases[2], target_ulong ram_sizes[2],
+ uint32_t sysclk, qemu_irq **picp,
+ ram_addr_t *offsetp, int do_init)
+{
+ clk_setup_t clk_setup[PPC405EP_CLK_NB], tlb_clk_setup;
+ qemu_irq dma_irqs[4], gpt_irqs[5], mal_irqs[4];
+ CPUState *env;
+ ppc4xx_mmio_t *mmio;
+ qemu_irq *pic, *irqs;
+ ram_addr_t offset;
+ int i;
+
+ memset(clk_setup, 0, sizeof(clk_setup));
+ /* init CPUs */
+ env = ppc405_init("405ep", &clk_setup[PPC405EP_CPU_CLK],
+ &tlb_clk_setup, sysclk);
+ clk_setup[PPC405EP_CPU_CLK].cb = tlb_clk_setup.cb;
+ clk_setup[PPC405EP_CPU_CLK].opaque = tlb_clk_setup.opaque;
+ /* Internal devices init */
+ /* Memory mapped devices registers */
+ mmio = ppc4xx_mmio_init(env, 0xEF600000);
+ /* PLB arbitrer */
+ ppc4xx_plb_init(env);
+ /* PLB to OPB bridge */
+ ppc4xx_pob_init(env);
+ /* OBP arbitrer */
+ ppc4xx_opba_init(env, mmio, 0x600);
+ /* Universal interrupt controller */
+ irqs = qemu_mallocz(sizeof(qemu_irq) * PPCUIC_OUTPUT_NB);
+ irqs[PPCUIC_OUTPUT_INT] =
+ ((qemu_irq *)env->irq_inputs)[PPC405_INPUT_INT];
+ irqs[PPCUIC_OUTPUT_CINT] =
+ ((qemu_irq *)env->irq_inputs)[PPC405_INPUT_CINT];
+ pic = ppcuic_init(env, irqs, 0x0C0, 0, 1);
+ *picp = pic;
+ /* SDRAM controller */
+ ppc405_sdram_init(env, pic[14], 2, ram_bases, ram_sizes, do_init);
+ offset = 0;
+ for (i = 0; i < 2; i++)
+ offset += ram_sizes[i];
+ /* External bus controller */
+ ppc405_ebc_init(env);
+ /* DMA controller */
+ dma_irqs[0] = pic[26];
+ dma_irqs[1] = pic[25];
+ dma_irqs[2] = pic[24];
+ dma_irqs[3] = pic[23];
+ ppc405_dma_init(env, dma_irqs);
+ /* IIC controller */
+ ppc405_i2c_init(env, mmio, 0x500, pic[29]);
+ /* GPIO */
+ ppc405_gpio_init(env, mmio, 0x700);
+ /* Serial ports */
+ if (serial_hds[0] != NULL) {
+ ppc405_serial_init(env, mmio, 0x300, pic[31], serial_hds[0]);
+ }
+ if (serial_hds[1] != NULL) {
+ ppc405_serial_init(env, mmio, 0x400, pic[30], serial_hds[1]);
+ }
+ /* OCM */
+ ppc405_ocm_init(env, ram_sizes[0] + ram_sizes[1]);
+ offset += 4096;
+ /* GPT */
+ gpt_irqs[0] = pic[12];
+ gpt_irqs[1] = pic[11];
+ gpt_irqs[2] = pic[10];
+ gpt_irqs[3] = pic[9];
+ gpt_irqs[4] = pic[8];
+ ppc4xx_gpt_init(env, mmio, 0x000, gpt_irqs);
+ /* PCI */
+ /* Uses pic[28], pic[15], pic[13] */
+ /* MAL */
+ mal_irqs[0] = pic[20];
+ mal_irqs[1] = pic[19];
+ mal_irqs[2] = pic[18];
+ mal_irqs[3] = pic[17];
+ ppc405_mal_init(env, mal_irqs);
+ /* Ethernet */
+ /* Uses pic[22], pic[16], pic[14] */
+ /* CPU control */
+ ppc405ep_cpc_init(env, clk_setup, sysclk);
+ *offsetp = offset;
+
+ return env;
+}
Modified: trunk/src/host/qemu-neo1973/hw/ppc_chrp.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/ppc_chrp.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/ppc_chrp.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -1,7 +1,7 @@
/*
* QEMU PPC CHRP/PMAC hardware System Emulator
*
- * Copyright (c) 2004 Fabrice Bellard
+ * Copyright (c) 2004-2007 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
@@ -23,6 +23,9 @@
*/
#include "vl.h"
+/* SMP is not enabled, for now */
+#define MAX_CPUS 1
+
#define BIOS_FILENAME "ppc_rom.bin"
#define VGABIOS_FILENAME "video.x"
#define NVRAM_SIZE 0x2000
@@ -45,7 +48,7 @@
static void dbdma_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
{
- printf("%s: 0x%08x <= 0x%08x\n", __func__, addr, value);
+ printf("%s: 0x" PADDRX " <= 0x%08x\n", __func__, addr, value);
}
static void dbdma_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
@@ -58,7 +61,7 @@
static uint32_t dbdma_readb (void *opaque, target_phys_addr_t addr)
{
- printf("%s: 0x%08x => 0x00000000\n", __func__, addr);
+ printf("%s: 0x" PADDRX " => 0x00000000\n", __func__, addr);
return 0;
}
@@ -258,17 +261,12 @@
/* R6 = x, R7 = y, R8 = visible, R9 = data */
break;
default:
- fprintf(stderr, "unsupported OSI call R5=%08x\n", env->gpr[5]);
+ fprintf(stderr, "unsupported OSI call R5=" REGX "\n", env->gpr[5]);
break;
}
return 1; /* osi_call handled */
}
-/* XXX: suppress that */
-static void pic_irq_request(void *opaque, int level)
-{
-}
-
static uint8_t nvram_chksum(const uint8_t *buf, int n)
{
int sum, i;
@@ -292,18 +290,18 @@
}
/* PowerPC CHRP hardware initialisation */
-static void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device,
- DisplayState *ds, const char **fd_filename,
- int snapshot,
- const char *kernel_filename,
- const char *kernel_cmdline,
- const char *initrd_filename,
- int is_heathrow)
+static void ppc_chrp_init (int ram_size, int vga_ram_size, int boot_device,
+ DisplayState *ds, const char **fd_filename,
+ int snapshot,
+ const char *kernel_filename,
+ const char *kernel_cmdline,
+ const char *initrd_filename,
+ const char *cpu_model,
+ int is_heathrow)
{
- CPUState *env;
+ CPUState *env, *envs[MAX_CPUS];
char buf[1024];
- SetIRQFunc *set_irq;
- void *pic;
+ qemu_irq *pic, **openpic_irqs;
m48t59_t *nvram;
int unin_memory;
int linux_boot, i;
@@ -313,39 +311,36 @@
PCIBus *pci_bus;
const char *arch_name;
int vga_bios_size, bios_size;
+ qemu_irq *dummy_irq;
linux_boot = (kernel_filename != NULL);
/* init CPUs */
env = cpu_init();
+ qemu_register_reset(&cpu_ppc_reset, env);
register_savevm("cpu", 0, 3, cpu_save, cpu_load, env);
- /* Register CPU as a 74x/75x */
+ /* Default CPU is a generic 74x/75x */
+ if (cpu_model == NULL)
+ cpu_model = "750";
/* XXX: CPU model (or PVR) should be provided on command line */
// ppc_find_by_name("750gx", &def); // Linux boot OK
// ppc_find_by_name("750fx", &def); // Linux boot OK
/* Linux does not boot on 750cxe (and probably other 750cx based)
* because it assumes it has 8 IBAT & DBAT pairs as it only have 4.
*/
- // ppc_find_by_name("750cxe", &def);
- // ppc_find_by_name("750p", &def);
- // ppc_find_by_name("740p", &def);
- ppc_find_by_name("750", &def);
- // ppc_find_by_name("740", &def);
- // ppc_find_by_name("G3", &def);
- // ppc_find_by_name("604r", &def);
- // ppc_find_by_name("604e", &def);
- // ppc_find_by_name("604", &def);
+ ppc_find_by_name(cpu_model, &def);
if (def == NULL) {
cpu_abort(env, "Unable to find PowerPC CPU definition\n");
}
- cpu_ppc_register(env, def);
+ for (i = 0; i < smp_cpus; i++) {
+ cpu_ppc_register(env, def);
+ /* Set time-base frequency to 100 Mhz */
+ cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL);
+ env->osi_call = vga_osi_call;
+ envs[i] = env;
+ }
- /* Set time-base frequency to 100 Mhz */
- cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL);
-
- env->osi_call = vga_osi_call;
-
/* allocate RAM */
cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
@@ -354,11 +349,11 @@
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME);
bios_size = load_image(buf, phys_ram_base + bios_offset);
if (bios_size < 0 || bios_size > BIOS_SIZE) {
- fprintf(stderr, "qemu: could not load PowerPC bios '%s'\n", buf);
+ cpu_abort(env, "qemu: could not load PowerPC bios '%s'\n", buf);
exit(1);
}
bios_size = (bios_size + 0xfff) & ~0xfff;
- cpu_register_physical_memory((uint32_t)(-bios_size),
+ cpu_register_physical_memory((uint32_t)(-bios_size),
bios_size, bios_offset | IO_MEM_ROM);
/* allocate and load VGA BIOS */
@@ -387,8 +382,8 @@
/* now we can load the kernel */
kernel_size = load_image(kernel_filename, phys_ram_base + kernel_base);
if (kernel_size < 0) {
- fprintf(stderr, "qemu: could not load kernel '%s'\n",
- kernel_filename);
+ cpu_abort(env, "qemu: could not load kernel '%s'\n",
+ kernel_filename);
exit(1);
}
/* load initrd */
@@ -397,8 +392,8 @@
initrd_size = load_image(initrd_filename,
phys_ram_base + initrd_base);
if (initrd_size < 0) {
- fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
- initrd_filename);
+ cpu_abort(env, "qemu: could not load initial ram disk '%s'\n",
+ initrd_filename);
exit(1);
}
} else {
@@ -415,34 +410,37 @@
if (is_heathrow) {
isa_mem_base = 0x80000000;
-
+
/* Register 2 MB of ISA IO space */
isa_mmio_init(0xfe000000, 0x00200000);
/* init basic PC hardware */
+ if (PPC_INPUT(env) != PPC_FLAGS_INPUT_6xx) {
+ cpu_abort(env, "Only 6xx bus is supported on heathrow machine\n");
+ exit(1);
+ }
pic = heathrow_pic_init(&heathrow_pic_mem_index);
- set_irq = heathrow_pic_set_irq;
pci_bus = pci_grackle_init(0xfec00000, pic);
- pci_vga_init(pci_bus, ds, phys_ram_base + ram_size,
+ pci_vga_init(pci_bus, ds, phys_ram_base + ram_size,
ram_size, vga_ram_size,
vga_bios_offset, vga_bios_size);
/* XXX: suppress that */
- isa_pic = pic_init(pic_irq_request, NULL);
+ dummy_irq = i8259_init(NULL);
/* XXX: use Mac Serial port */
- serial_init(&pic_set_irq_new, isa_pic, 0x3f8, 4, serial_hds[0]);
+ serial_init(0x3f8, dummy_irq[4], serial_hds[0]);
for(i = 0; i < nb_nics; i++) {
if (!nd_table[i].model)
nd_table[i].model = "ne2k_pci";
- pci_nic_init(pci_bus, &nd_table[i]);
+ pci_nic_init(pci_bus, &nd_table[i], -1);
}
pci_cmd646_ide_init(pci_bus, &bs_table[0], 0);
/* cuda also initialize ADB */
- cuda_mem_index = cuda_init(set_irq, pic, 0x12);
+ cuda_mem_index = cuda_init(pic[0x12]);
adb_kbd_init(&adb_bus);
adb_mouse_init(&adb_bus);
@@ -454,22 +452,64 @@
}
macio_init(pci_bus, 0x0017);
-
- nvram = m48t59_init(8, 0xFFF04000, 0x0074, NVRAM_SIZE, 59);
-
+
+ nvram = m48t59_init(dummy_irq[8], 0xFFF04000, 0x0074, NVRAM_SIZE, 59);
+
arch_name = "HEATHROW";
} else {
isa_mem_base = 0x80000000;
-
+
/* Register 8 MB of ISA IO space */
isa_mmio_init(0xf2000000, 0x00800000);
-
+
/* UniN init */
unin_memory = cpu_register_io_memory(0, unin_read, unin_write, NULL);
cpu_register_physical_memory(0xf8000000, 0x00001000, unin_memory);
- pic = openpic_init(NULL, &openpic_mem_index, 1, &env);
- set_irq = openpic_set_irq;
+ openpic_irqs = qemu_mallocz(smp_cpus * sizeof(qemu_irq *));
+ openpic_irqs[0] =
+ qemu_mallocz(smp_cpus * sizeof(qemu_irq) * OPENPIC_OUTPUT_NB);
+ for (i = 0; i < smp_cpus; i++) {
+ /* Mac99 IRQ connection between OpenPIC outputs pins
+ * and PowerPC input pins
+ */
+ switch (PPC_INPUT(env)) {
+ case PPC_FLAGS_INPUT_6xx:
+ openpic_irqs[i] = openpic_irqs[0] + (i * OPENPIC_OUTPUT_NB);
+ openpic_irqs[i][OPENPIC_OUTPUT_INT] =
+ ((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_INT];
+ openpic_irqs[i][OPENPIC_OUTPUT_CINT] =
+ ((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_INT];
+ openpic_irqs[i][OPENPIC_OUTPUT_MCK] =
+ ((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_MCP];
+ /* Not connected ? */
+ openpic_irqs[i][OPENPIC_OUTPUT_DEBUG] = NULL;
+ /* Check this */
+ openpic_irqs[i][OPENPIC_OUTPUT_RESET] =
+ ((qemu_irq *)env->irq_inputs)[PPC6xx_INPUT_HRESET];
+ break;
+ case PPC_FLAGS_INPUT_970:
+ openpic_irqs[i] = openpic_irqs[0] + (i * OPENPIC_OUTPUT_NB);
+ openpic_irqs[i][OPENPIC_OUTPUT_INT] =
+ ((qemu_irq *)env->irq_inputs)[PPC970_INPUT_INT];
+ openpic_irqs[i][OPENPIC_OUTPUT_CINT] =
+ ((qemu_irq *)env->irq_inputs)[PPC970_INPUT_INT];
+ openpic_irqs[i][OPENPIC_OUTPUT_MCK] =
+ ((qemu_irq *)env->irq_inputs)[PPC970_INPUT_MCP];
+ /* Not connected ? */
+ openpic_irqs[i][OPENPIC_OUTPUT_DEBUG] = NULL;
+ /* Check this */
+ openpic_irqs[i][OPENPIC_OUTPUT_RESET] =
+ ((qemu_irq *)env->irq_inputs)[PPC970_INPUT_HRESET];
+ break;
+ default:
+ cpu_abort(env,
+ "Only bus model not supported on mac99 machine\n");
+ exit(1);
+ }
+ }
+ pic = openpic_init(NULL, &openpic_mem_index, smp_cpus,
+ openpic_irqs, NULL);
pci_bus = pci_pmac_init(pic);
/* init basic PC hardware */
pci_vga_init(pci_bus, ds, phys_ram_base + ram_size,
@@ -477,30 +517,30 @@
vga_bios_offset, vga_bios_size);
/* XXX: suppress that */
- isa_pic = pic_init(pic_irq_request, NULL);
-
+ dummy_irq = i8259_init(NULL);
+
/* XXX: use Mac Serial port */
- serial_init(&pic_set_irq_new, isa_pic, 0x3f8, 4, serial_hds[0]);
-
+ serial_init(0x3f8, dummy_irq[4], serial_hds[0]);
for(i = 0; i < nb_nics; i++) {
- pci_ne2000_init(pci_bus, &nd_table[i]);
+ if (!nd_table[i].model)
+ nd_table[i].model = "ne2k_pci";
+ pci_nic_init(pci_bus, &nd_table[i], -1);
}
-
#if 1
- ide0_mem_index = pmac_ide_init(&bs_table[0], set_irq, pic, 0x13);
- ide1_mem_index = pmac_ide_init(&bs_table[2], set_irq, pic, 0x14);
+ ide0_mem_index = pmac_ide_init(&bs_table[0], pic[0x13]);
+ ide1_mem_index = pmac_ide_init(&bs_table[2], pic[0x14]);
#else
pci_cmd646_ide_init(pci_bus, &bs_table[0], 0);
#endif
/* cuda also initialize ADB */
- cuda_mem_index = cuda_init(set_irq, pic, 0x19);
+ cuda_mem_index = cuda_init(pic[0x19]);
adb_kbd_init(&adb_bus);
adb_mouse_init(&adb_bus);
macio_init(pci_bus, 0x0022);
- nvram = m48t59_init(8, 0xFFF04000, 0x0074, NVRAM_SIZE, 59);
+ nvram = m48t59_init(dummy_irq[8], 0xFFF04000, 0x0074, NVRAM_SIZE, 59);
arch_name = "MAC99";
}
@@ -525,30 +565,32 @@
register_ioport_write(0x0F00, 4, 1, &PPC_debug_write, NULL);
}
-static void ppc_core99_init(int ram_size, int vga_ram_size, int boot_device,
- DisplayState *ds, const char **fd_filename,
- int snapshot,
- const char *kernel_filename,
- const char *kernel_cmdline,
- const char *initrd_filename)
+static void ppc_core99_init (int ram_size, int vga_ram_size, int boot_device,
+ DisplayState *ds, const char **fd_filename,
+ int snapshot,
+ const char *kernel_filename,
+ const char *kernel_cmdline,
+ const char *initrd_filename,
+ const char *cpu_model)
{
ppc_chrp_init(ram_size, vga_ram_size, boot_device,
ds, fd_filename, snapshot,
kernel_filename, kernel_cmdline,
- initrd_filename, 0);
+ initrd_filename, cpu_model, 0);
}
-static void ppc_heathrow_init(int ram_size, int vga_ram_size, int boot_device,
- DisplayState *ds, const char **fd_filename,
- int snapshot,
- const char *kernel_filename,
- const char *kernel_cmdline,
- const char *initrd_filename)
+static void ppc_heathrow_init (int ram_size, int vga_ram_size, int boot_device,
+ DisplayState *ds, const char **fd_filename,
+ int snapshot,
+ const char *kernel_filename,
+ const char *kernel_cmdline,
+ const char *initrd_filename,
+ const char *cpu_model)
{
ppc_chrp_init(ram_size, vga_ram_size, boot_device,
ds, fd_filename, snapshot,
kernel_filename, kernel_cmdline,
- initrd_filename, 1);
+ initrd_filename, cpu_model, 1);
}
QEMUMachine core99_machine = {
Modified: trunk/src/host/qemu-neo1973/hw/ppc_prep.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/ppc_prep.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/ppc_prep.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -1,7 +1,7 @@
/*
* QEMU PPC PREP hardware System Emulator
*
- * Copyright (c) 2003-2004 Jocelyn Mayer
+ * Copyright (c) 2003-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
@@ -84,29 +84,22 @@
#endif
}
-static uint32_t speaker_ioport_read(void *opaque, uint32_t addr)
+static uint32_t speaker_ioport_read (void *opaque, uint32_t addr)
{
#if 0
int out;
out = pit_get_out(pit, 2, qemu_get_clock(vm_clock));
dummy_refresh_clock ^= 1;
return (speaker_data_on << 1) | pit_get_gate(pit, 2) | (out << 5) |
- (dummy_refresh_clock << 4);
+ (dummy_refresh_clock << 4);
#endif
return 0;
}
-static void pic_irq_request(void *opaque, int level)
-{
- if (level)
- cpu_interrupt(first_cpu, CPU_INTERRUPT_HARD);
- else
- cpu_reset_interrupt(first_cpu, CPU_INTERRUPT_HARD);
-}
-
/* PCI intack register */
/* Read-only register (?) */
-static void _PPC_intack_write (void *opaque, target_phys_addr_t addr, uint32_t value)
+static void _PPC_intack_write (void *opaque,
+ target_phys_addr_t addr, uint32_t value)
{
// printf("%s: 0x%08x => 0x%08x\n", __func__, addr, value);
}
@@ -294,7 +287,7 @@
/* Special port 92 */
/* Check soft reset asked */
if (val & 0x01) {
- // cpu_interrupt(first_cpu, CPU_INTERRUPT_RESET);
+ // cpu_interrupt(first_cpu, PPC_INTERRUPT_RESET);
}
/* Check LE mode */
if (val & 0x02) {
@@ -518,10 +511,12 @@
#define NVRAM_SIZE 0x2000
/* PowerPC PREP hardware initialisation */
-static void ppc_prep_init(int ram_size, int vga_ram_size, int boot_device,
- DisplayState *ds, const char **fd_filename, int snapshot,
- const char *kernel_filename, const char *kernel_cmdline,
- const char *initrd_filename)
+static void ppc_prep_init (int ram_size, int vga_ram_size, int boot_device,
+ DisplayState *ds, const char **fd_filename,
+ int snapshot, const char *kernel_filename,
+ const char *kernel_cmdline,
+ const char *initrd_filename,
+ const char *cpu_model)
{
CPUState *env;
char buf[1024];
@@ -532,23 +527,24 @@
uint32_t kernel_base, kernel_size, initrd_base, initrd_size;
ppc_def_t *def;
PCIBus *pci_bus;
+ qemu_irq *i8259;
sysctrl = qemu_mallocz(sizeof(sysctrl_t));
if (sysctrl == NULL)
- return;
+ return;
linux_boot = (kernel_filename != NULL);
-
+
/* init CPUs */
env = cpu_init();
+ qemu_register_reset(&cpu_ppc_reset, env);
register_savevm("cpu", 0, 3, cpu_save, cpu_load, env);
-
- /* Register CPU as a 604 */
- /* XXX: CPU model (or PVR) should be provided on command line */
- // ppc_find_by_name("604r", &def);
- // ppc_find_by_name("604e", &def);
- ppc_find_by_name("604", &def);
+
+ /* Default CPU is a 604 */
+ if (cpu_model == NULL)
+ cpu_model = "604";
+ ppc_find_by_name(cpu_model, &def);
if (def == NULL) {
cpu_abort(env, "Unable to find PowerPC CPU definition\n");
}
@@ -564,11 +560,11 @@
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME);
bios_size = load_image(buf, phys_ram_base + bios_offset);
if (bios_size < 0 || bios_size > BIOS_SIZE) {
- fprintf(stderr, "qemu: could not load PPC PREP bios '%s'\n", buf);
+ cpu_abort(env, "qemu: could not load PPC PREP bios '%s'\n", buf);
exit(1);
}
bios_size = (bios_size + 0xfff) & ~0xfff;
- cpu_register_physical_memory((uint32_t)(-bios_size),
+ cpu_register_physical_memory((uint32_t)(-bios_size),
bios_size, bios_offset | IO_MEM_ROM);
if (linux_boot) {
@@ -576,8 +572,8 @@
/* now we can load the kernel */
kernel_size = load_image(kernel_filename, phys_ram_base + kernel_base);
if (kernel_size < 0) {
- fprintf(stderr, "qemu: could not load kernel '%s'\n",
- kernel_filename);
+ cpu_abort(env, "qemu: could not load kernel '%s'\n",
+ kernel_filename);
exit(1);
}
/* load initrd */
@@ -586,8 +582,8 @@
initrd_size = load_image(initrd_filename,
phys_ram_base + initrd_base);
if (initrd_size < 0) {
- fprintf(stderr, "qemu: could not load initial ram disk '%s'\n",
- initrd_filename);
+ cpu_abort(env, "qemu: could not load initial ram disk '%s'\n",
+ initrd_filename);
exit(1);
}
} else {
@@ -603,7 +599,12 @@
}
isa_mem_base = 0xc0000000;
- pci_bus = pci_prep_init();
+ if (PPC_INPUT(env) != PPC_FLAGS_INPUT_6xx) {
+ cpu_abort(env, "Only 6xx bus is supported on PREP machine\n");
+ exit(1);
+ }
+ i8259 = i8259_init(first_cpu->irq_inputs[PPC6xx_INPUT_INT]);
+ pci_bus = pci_prep_init(i8259);
// pci_bus = i440fx_init();
/* Register 8 MB of ISA IO space (needed for non-contiguous map) */
PPC_io_memory = cpu_register_io_memory(0, PPC_prep_io_read,
@@ -613,35 +614,35 @@
/* init basic PC hardware */
pci_vga_init(pci_bus, ds, phys_ram_base + ram_size, ram_size,
vga_ram_size, 0, 0);
- rtc_init(0x70, 8);
// openpic = openpic_init(0x00000000, 0xF0000000, 1);
- isa_pic = pic_init(pic_irq_request, first_cpu);
- // pit = pit_init(0x40, 0);
+ // pit = pit_init(0x40, i8259[0]);
+ rtc_init(0x70, i8259[8]);
- serial_init(&pic_set_irq_new, isa_pic, 0x3f8, 4, serial_hds[0]);
+ serial_init(0x3f8, i8259[4], serial_hds[0]);
nb_nics1 = nb_nics;
if (nb_nics1 > NE2000_NB_MAX)
nb_nics1 = NE2000_NB_MAX;
for(i = 0; i < nb_nics1; i++) {
if (nd_table[0].model == NULL
|| strcmp(nd_table[0].model, "ne2k_isa") == 0) {
- isa_ne2000_init(ne2000_io[i], ne2000_irq[i], &nd_table[i]);
+ isa_ne2000_init(ne2000_io[i], i8259[ne2000_irq[i]], &nd_table[i]);
} else {
- fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model);
+ /* Why ? */
+ cpu_abort(env, "qemu: Unsupported NIC: %s\n", nd_table[0].model);
exit (1);
}
}
for(i = 0; i < 2; i++) {
- isa_ide_init(ide_iobase[i], ide_iobase2[i], ide_irq[i],
+ isa_ide_init(ide_iobase[i], ide_iobase2[i], i8259[ide_irq[i]],
bs_table[2 * i], bs_table[2 * i + 1]);
}
- kbd_init();
+ i8042_init(i8259[1], i8259[12], 0x60);
DMA_init(1);
// AUD_init();
// SB16_init();
- fdctrl_init(6, 2, 0, 0x3f0, fd_table);
+ fdctrl_init(i8259[6], 2, 0, 0x3f0, fd_table);
/* Register speaker port */
register_ioport_read(0x61, 1, 1, speaker_ioport_read, NULL);
@@ -668,7 +669,7 @@
usb_ohci_init_pci(pci_bus, 3, -1);
}
- nvram = m48t59_init(8, 0, 0x0074, NVRAM_SIZE, 59);
+ nvram = m48t59_init(i8259[8], 0, 0x0074, NVRAM_SIZE, 59);
if (nvram == NULL)
return;
sysctrl->nvram = nvram;
Modified: trunk/src/host/qemu-neo1973/hw/prep_pci.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/prep_pci.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/prep_pci.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -123,19 +123,19 @@
return (irq_num + (pci_dev->devfn >> 3)) & 1;
}
-static void prep_set_irq(void *pic, int irq_num, int level)
+static void prep_set_irq(qemu_irq *pic, int irq_num, int level)
{
- pic_set_irq(irq_num ? 11 : 9, level);
+ qemu_set_irq(pic[irq_num ? 11 : 9], level);
}
-PCIBus *pci_prep_init(void)
+PCIBus *pci_prep_init(qemu_irq *pic)
{
PREPPCIState *s;
PCIDevice *d;
int PPC_io_memory;
s = qemu_mallocz(sizeof(PREPPCIState));
- s->bus = pci_register_bus(prep_set_irq, prep_map_irq, NULL, 0, 2);
+ s->bus = pci_register_bus(prep_set_irq, prep_map_irq, pic, 0, 2);
register_ioport_write(0xcf8, 4, 4, pci_prep_addr_writel, s);
register_ioport_read(0xcf8, 4, 4, pci_prep_addr_readl, s);
Modified: trunk/src/host/qemu-neo1973/hw/ps2.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/ps2.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/ps2.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -324,6 +324,11 @@
}
}
+void ps2_mouse_fake_event(void *opaque)
+{
+ ps2_mouse_event(opaque, 1, 0, 0, 0);
+}
+
void ps2_write_mouse(void *opaque, int val)
{
PS2MouseState *s = (PS2MouseState *)opaque;
Modified: trunk/src/host/qemu-neo1973/hw/pxa.h
===================================================================
--- trunk/src/host/qemu-neo1973/hw/pxa.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/pxa.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -7,10 +7,8 @@
* This code is licenced under the GPL.
*/
#ifndef PXA_H
-# define PXA_H 1
+# define PXA_H "pxa.h"
-# include "arm_pic.h"
-
/* Interrupt numbers */
# define PXA2XX_PIC_SSP3 0
# define PXA2XX_PIC_USBH2 2
@@ -22,10 +20,12 @@
# define PXA2XX_PIC_GPIO_1 9
# define PXA2XX_PIC_GPIO_X 10
# define PXA2XX_PIC_I2S 13
+# define PXA26X_PIC_ASSP 15
# define PXA25X_PIC_NSSP 16
# define PXA27X_PIC_SSP2 16
# define PXA2XX_PIC_LCD 17
# define PXA2XX_PIC_I2C 18
+# define PXA2XX_PIC_ICP 19
# define PXA2XX_PIC_STUART 20
# define PXA2XX_PIC_BTUART 21
# define PXA2XX_PIC_FFUART 22
@@ -47,6 +47,8 @@
# define PXA2XX_TX_RQ_SSP1 14
# define PXA2XX_RX_RQ_SSP2 15
# define PXA2XX_TX_RQ_SSP2 16
+# define PXA2XX_RX_RQ_ICP 17
+# define PXA2XX_TX_RQ_ICP 18
# define PXA2XX_RX_RQ_STUART 19
# define PXA2XX_TX_RQ_STUART 20
# define PXA2XX_RX_RQ_MMCI 21
@@ -55,23 +57,22 @@
# define PXA2XX_RX_RQ_SSP3 66
# define PXA2XX_TX_RQ_SSP3 67
-# define PXA2XX_RAM_BASE 0xa0000000
+# define PXA2XX_SDRAM_BASE 0xa0000000
+# define PXA2XX_INTERNAL_BASE 0x5c000000
/* pxa2xx_pic.c */
-struct pxa2xx_pic_state_s;
-struct pxa2xx_pic_state_s *pxa2xx_pic_init(target_phys_addr_t base,
- CPUState *env, int parent_irq, int parent_fiq);
+qemu_irq *pxa2xx_pic_init(target_phys_addr_t base, CPUState *env);
/* pxa2xx_timer.c */
void pxa25x_timer_init(target_phys_addr_t base,
- void *pic, int irq, CPUState *cpustate);
+ qemu_irq *irqs, CPUState *cpustate);
void pxa27x_timer_init(target_phys_addr_t base,
- void *pic, int irq, CPUState *cpustate);
+ qemu_irq *irqs, qemu_irq irq4, CPUState *cpustate);
/* pxa2xx_gpio.c */
struct pxa2xx_gpio_info_s;
struct pxa2xx_gpio_info_s *pxa2xx_gpio_init(target_phys_addr_t base,
- CPUState *env, void *pic, int lines);
+ CPUState *env, qemu_irq *pic, int lines);
void pxa2xx_gpio_set(struct pxa2xx_gpio_info_s *s, int line, int level);
void pxa2xx_gpio_handler_set(struct pxa2xx_gpio_info_s *s, int line,
gpio_handler_t handler, void *opaque);
@@ -81,15 +82,15 @@
/* pxa2xx_dma.c */
struct pxa2xx_dma_state_s;
struct pxa2xx_dma_state_s *pxa255_dma_init(target_phys_addr_t base,
- void *pic, int irq);
+ qemu_irq irq);
struct pxa2xx_dma_state_s *pxa27x_dma_init(target_phys_addr_t base,
- void *pic, int irq);
+ qemu_irq irq);
void pxa2xx_dma_request(struct pxa2xx_dma_state_s *s, int req_num, int on);
/* pxa2xx_lcd.c */
struct pxa2xx_lcdc_s;
struct pxa2xx_lcdc_s *pxa2xx_lcdc_init(target_phys_addr_t base,
- void *pic, DisplayState *ds);
+ qemu_irq irq, DisplayState *ds);
void pxa2xx_lcd_vsync_cb(struct pxa2xx_lcdc_s *s,
void (*cb)(void *opaque), void *opaque);
void pxa2xx_lcdc_oritentation(void *opaque, int angle);
@@ -97,7 +98,7 @@
/* pxa2xx_mmci.c */
struct pxa2xx_mmci_s;
struct pxa2xx_mmci_s *pxa2xx_mmci_init(target_phys_addr_t base,
- void *pic, void *dma);
+ qemu_irq irq, void *dma);
void pxa2xx_mmci_handlers(struct pxa2xx_mmci_s *s, void *opaque,
void (*readonly_cb)(void *, int),
void (*coverswitch_cb)(void *, int));
@@ -107,54 +108,30 @@
struct pxa2xx_pcmcia_s *pxa2xx_pcmcia_init(target_phys_addr_t base);
int pxa2xx_pcmcia_attach(void *opaque, struct pcmcia_card_s *card);
int pxa2xx_pcmcia_dettach(void *opaque);
-void pxa2xx_pcmcia_set_irq_cb(void *opaque, void (*set_irq)(void *opaque,
- int line, int level), int irq, int cd_irq, void *pic);
+void pxa2xx_pcmcia_set_irq_cb(void *opaque, qemu_irq irq, qemu_irq cd_irq);
-static struct {
- target_phys_addr_t io_base;
- int irq;
-} pxa255_serial[] = {
- { 0x40100000, PXA2XX_PIC_FFUART },
- { 0x40200000, PXA2XX_PIC_BTUART },
- { 0x40700000, PXA2XX_PIC_STUART },
- { 0x41600000, PXA25X_PIC_HWUART },
- { 0, 0 }
-}, pxa270_serial[] = {
- { 0x40100000, PXA2XX_PIC_FFUART },
- { 0x40200000, PXA2XX_PIC_BTUART },
- { 0x40700000, PXA2XX_PIC_STUART },
- { 0, 0 }
-};
-
-static struct {
- target_phys_addr_t io_base;
- int irq;
-} pxa27x_ssp[] = {
- { 0x41000000, PXA2XX_PIC_SSP },
- { 0x41700000, PXA27X_PIC_SSP2 },
- { 0x41900000, PXA2XX_PIC_SSP3 },
- { 0, 0 }
-};
-
-/* The CPU is also modeled as an interrupt controller. */
-# define PXA2XX_PIC_CPU_IRQ 0
-# define PXA2XX_PIC_CPU_FIQ 1
-
+/* pxa2xx.c */
struct pxa2xx_ssp_s;
+void pxa2xx_ssp_attach(struct pxa2xx_ssp_s *port,
+ uint32_t (*readfn)(void *opaque),
+ void (*writefn)(void *opaque, uint32_t value), void *opaque);
+
struct pxa2xx_i2c_s;
struct pxa2xx_i2s_s;
+struct pxa2xx_fir_s;
struct pxa2xx_state_s {
CPUState *env;
- struct pxa2xx_pic_state_s *pic;
+ qemu_irq *pic;
struct pxa2xx_dma_state_s *dma;
struct pxa2xx_gpio_info_s *gpio;
struct pxa2xx_lcdc_s *lcd;
struct pxa2xx_ssp_s **ssp;
+ struct pxa2xx_i2c_s *i2c[2];
struct pxa2xx_mmci_s *mmc;
struct pxa2xx_pcmcia_s *pcmcia[2];
- struct pxa2xx_i2c_s *i2c[2];
struct pxa2xx_i2s_s *i2s;
+ struct pxa2xx_fir_s *fir;
/* Power management */
target_phys_addr_t pm_base;
@@ -200,1250 +177,22 @@
QEMUTimer *rtc_pi;
};
-# define PMCR 0x00 /* Power Manager Control Register */
-# define PSSR 0x04 /* Power Manager Sleep Status Register */
-# define PSPR 0x08 /* Power Manager Scratch-Pad Register */
-# define PWER 0x0c /* Power Manager Wake-Up Enable Register */
-# define PRER 0x10 /* Power Manager Rising-Edge Detect Enable Register */
-# define PFER 0x14 /* Power Manager Falling-Edge Detect Enable Register */
-# define PEDR 0x18 /* Power Manager Edge-Detect Status Register */
-# define PCFR 0x1c /* Power Manager General Configuration Register */
-# define PGSR0 0x20 /* Power Manager GPIO Sleep-State Register 0 */
-# define PGSR1 0x24 /* Power Manager GPIO Sleep-State Register 1 */
-# define PGSR2 0x28 /* Power Manager GPIO Sleep-State Register 2 */
-# define PGSR3 0x2c /* Power Manager GPIO Sleep-State Register 3 */
-# define RCSR 0x30 /* Reset Controller Status Register */
-# define PSLR 0x34 /* Power Manager Sleep Configuration Register */
-# define PTSR 0x38 /* Power Manager Standby Configuration Register */
-# define PVCR 0x40 /* Power Manager Voltage Change Control Register */
-# define PUCR 0x4c /* Power Manager USIM Card Control/Status Register */
-# define PKWR 0x50 /* Power Manager Keyboard Wake-Up Enable Register */
-# define PKSR 0x54 /* Power Manager Keyboard Level-Detect Status */
-# define PCMD0 0x80 /* Power Manager I2C Command Register File 0 */
-# define PCMD31 0xfc /* Power Manager I2C Command Register File 31 */
-
-static uint32_t pxa2xx_i2c_read(void *, target_phys_addr_t);
-static void pxa2xx_i2c_write(void *, target_phys_addr_t, uint32_t);
-
-static uint32_t pxa2xx_pm_read(void *opaque, target_phys_addr_t addr)
-{
- struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
- if (addr > s->pm_base + PCMD31) {
- /* Special case: PWRI2C registers appear in the same range. */
- return pxa2xx_i2c_read(s->i2c[1], addr);
- }
- addr -= s->pm_base;
-
- switch (addr) {
- case PMCR ... PCMD31:
- if (addr & 3)
- goto fail;
-
- return s->pm_regs[addr >> 2];
- default:
- fail:
- printf("%s: Bad register 0x%lx\n", __FUNCTION__, addr);
- break;
- }
- return 0;
-}
-
-static void pxa2xx_pm_write(void *opaque, target_phys_addr_t addr,
- uint32_t value)
-{
- struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
- if (addr > s->pm_base + PCMD31) {
- /* Special case: PWRI2C registers appear in the same range. */
- pxa2xx_i2c_write(s->i2c[1], addr, value);
- return;
- }
- addr -= s->pm_base;
-
- switch (addr) {
- case PMCR:
- s->pm_regs[addr >> 2] &= 0x15 & ~(value & 0x2a);
- s->pm_regs[addr >> 2] |= value & 0x15;
- break;
-
- case PSSR: /* Read-clean registers */
- case RCSR:
- case PKSR:
- s->pm_regs[addr >> 2] &= ~value;
- break;
-
- default: /* Read-write registers */
- if (addr >= PMCR && addr <= PCMD31 && !(addr & 3)) {
- s->pm_regs[addr >> 2] = value;
- break;
- }
-
- printf("%s: Bad register 0x%lx\n", __FUNCTION__, addr);
- break;
- }
-}
-
-static CPUReadMemoryFunc *pxa2xx_pm_readfn[] = {
- pxa2xx_pm_read,
- pxa2xx_pm_read,
- pxa2xx_pm_read,
-};
-
-static CPUWriteMemoryFunc *pxa2xx_pm_writefn[] = {
- pxa2xx_pm_write,
- pxa2xx_pm_write,
- pxa2xx_pm_write,
-};
-
-# define CCCR 0x00 /* Core Clock Configuration Register */
-# define CKEN 0x04 /* Clock Enable Register */
-# define OSCC 0x08 /* Oscillator Configuration Register */
-# define CCSR 0x0c /* Core Clock Status Register */
-
-static uint32_t pxa2xx_cm_read(void *opaque, target_phys_addr_t addr)
-{
- struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
- addr -= s->cm_base;
-
- switch (addr) {
- case CCCR:
- case CKEN:
- case OSCC:
- return s->cm_regs[addr >> 2];
-
- case CCSR:
- return s->cm_regs[CCCR >> 2] | (3 << 28);
-
- default:
- printf("%s: Bad register 0x%lx\n", __FUNCTION__, addr);
- break;
- }
- return 0;
-}
-
-static void pxa2xx_cm_write(void *opaque, target_phys_addr_t addr,
- uint32_t value)
-{
- struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
- addr -= s->cm_base;
-
- switch (addr) {
- case CCCR:
- case CKEN:
- s->cm_regs[addr >> 2] = value;
- break;
-
- case OSCC:
- s->cm_regs[addr >> 2] &= ~0x6e;
- s->cm_regs[addr >> 2] |= value & 0x6e;
- break;
-
- default:
- printf("%s: Bad register 0x%lx\n", __FUNCTION__, addr);
- break;
- }
-}
-
-static CPUReadMemoryFunc *pxa2xx_cm_readfn[] = {
- pxa2xx_cm_read,
- pxa2xx_cm_read,
- pxa2xx_cm_read,
-};
-
-static CPUWriteMemoryFunc *pxa2xx_cm_writefn[] = {
- pxa2xx_cm_write,
- pxa2xx_cm_write,
- pxa2xx_cm_write,
-};
-
-static uint32_t pxa2xx_clkpwr_read(void *opaque, int op2, int reg, int crm)
-{
- struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
-
- switch (reg) {
- case 6: /* Clock Configuration Register */
- return s->clkcfg;
-
- case 7: /* Power Mode Register */
- return 0;
-
- default:
- printf("%s: Bad register 0x%x\n", __FUNCTION__, reg);
- break;
- }
- return 0;
-}
-
-static void pxa2xx_clkpwr_write(void *opaque, int op2, int reg, int crm,
- uint32_t value)
-{
- struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
- static const char *pwrmode[8] = {
- "Normal", "Idle", "Deep-idle", "Standby",
- "Sleep", "reserved (!)", "reserved (!)", "Deep-sleep",
- };
-
- switch (reg) {
- case 6: /* Clock Configuration Register */
- s->clkcfg = value & 0xf;
- if (value & 2)
- printf("%s: CPU frequency change attempt\n", __FUNCTION__);
- break;
-
- case 7: /* Power Mode Register */
- if (value & 8)
- printf("%s: CPU voltage change attempt\n", __FUNCTION__);
- switch (value & 7) {
- case 0:
- /* Do nothing */
- break;
-
- case 1:
- /* Idle */
- if (!(s->cm_regs[CCCR] & (1 << 31))) { /* CPDIS */
- cpu_interrupt(s->env, CPU_INTERRUPT_HALT);
- break;
- }
- /* Fall through. */
-
- case 2:
- /* Deep-Idle */
- cpu_interrupt(s->env, CPU_INTERRUPT_HALT);
- s->pm_regs[RCSR >> 2] |= 0x8; /* Set GPR */
- goto message;
-
- case 3:
- cpu_reset(s->env);
- s->env->cp15.c1_sys = 0;
- s->env->cp15.c1_coproc = 0;
- s->env->cp15.c2 = 0;
- s->env->cp15.c3 = 0;
- s->pm_regs[PSSR >> 2] |= 0x8; /* Set STS */
- s->pm_regs[RCSR >> 2] |= 0x8; /* Set GPR */
-
- /*
- * The scratch-pad register is almost universally used
- * for storing the return address on suspend. For the
- * lack of a resuming bootloader, perform a jump
- * directly to that address.
- */
- memset(s->env->regs, 0, 4 * 15);
- s->env->regs[15] = s->pm_regs[PSPR >> 2];
-
-#if 0
- buffer = 0xe59ff000; /* ldr pc, [pc, #0] */
- cpu_physical_memory_write(0, &buffer, 4);
- buffer = s->pm_regs[PSPR >> 2];
- cpu_physical_memory_write(8, &buffer, 4);
-#endif
-
- /* Suspend */
- cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HALT);
-
- goto message;
-
- default:
- message:
- printf("%s: machine entered %s mode\n", __FUNCTION__,
- pwrmode[value & 7]);
- }
- break;
-
- default:
- printf("%s: Bad register 0x%x\n", __FUNCTION__, reg);
- break;
- }
-}
-
-/* Performace Monitoring registers */
-# define CPPMNC 0 /* Performance Monitor Control Register */
-# define CPCCNT 1 /* Clock Counter Register */
-# define CPINTEN 4 /* Interrupt Enable Register */
-# define CPFLAG 5 /* Overflow Flag Register */
-# define CPEVTSEL 8 /* Event Selection Register */
-
-# define CPPMN0 0 /* Performance Count Register 0 */
-# define CPPMN1 1 /* Performance Count Register 1 */
-# define CPPMN2 2 /* Performance Count Register 2 */
-# define CPPMN3 3 /* Performance Count Register 3 */
-
-static uint32_t pxa2xx_perf_read(void *opaque, int op2, int reg, int crm)
-{
- struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
-
- switch (reg) {
- case CPPMNC:
- return s->pmnc;
- case CPCCNT:
- if (s->pmnc & 1)
- return qemu_get_clock(vm_clock);
- else
- return 0;
- case CPINTEN:
- case CPFLAG:
- case CPEVTSEL:
- return 0;
-
- default:
- printf("%s: Bad register 0x%x\n", __FUNCTION__, reg);
- break;
- }
- return 0;
-}
-
-static void pxa2xx_perf_write(void *opaque, int op2, int reg, int crm,
- uint32_t value)
-{
- struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
-
- switch (reg) {
- case CPPMNC:
- s->pmnc = value;
- break;
-
- case CPCCNT:
- case CPINTEN:
- case CPFLAG:
- case CPEVTSEL:
- break;
-
- default:
- printf("%s: Bad register 0x%x\n", __FUNCTION__, reg);
- break;
- }
-}
-
-static uint32_t pxa2xx_cp14_read(void *opaque, int op2, int reg, int crm)
-{
- switch (crm) {
- case 0:
- return pxa2xx_clkpwr_read(opaque, op2, reg, crm);
- case 1:
- return pxa2xx_perf_read(opaque, op2, reg, crm);
- case 2:
- switch (reg) {
- case CPPMN0:
- case CPPMN1:
- case CPPMN2:
- case CPPMN3:
- return 0;
- }
- /* Fall through */
- default:
- printf("%s: Bad register 0x%x\n", __FUNCTION__, reg);
- break;
- }
- return 0;
-}
-
-static void pxa2xx_cp14_write(void *opaque, int op2, int reg, int crm,
- uint32_t value)
-{
- switch (crm) {
- case 0:
- pxa2xx_clkpwr_write(opaque, op2, reg, crm, value);
- break;
- case 1:
- pxa2xx_perf_write(opaque, op2, reg, crm, value);
- break;
- case 2:
- switch (reg) {
- case CPPMN0:
- case CPPMN1:
- case CPPMN2:
- case CPPMN3:
- return;
- }
- /* Fall through */
- default:
- printf("%s: Bad register 0x%x\n", __FUNCTION__, reg);
- break;
- }
-}
-
-# define MDCNFG 0x00 /* SDRAM Configuration Register */
-# define MDREFR 0x04 /* SDRAM Refresh Control Register */
-# define MSC0 0x08 /* Static Memory Control Register 0 */
-# define MSC1 0x0c /* Static Memory Control Register 1 */
-# define MSC2 0x10 /* Static Memory Control Register 2 */
-# define MECR 0x14 /* Expansion Memory Bus Config Register */
-# define SXCNFG 0x1c /* Synchronous Static Memory Config Register */
-# define MCMEM0 0x28 /* PC Card Memory Socket 0 Timing Register */
-# define MCMEM1 0x2c /* PC Card Memory Socket 1 Timing Register */
-# define MCATT0 0x30 /* PC Card Attribute Socket 0 Register */
-# define MCATT1 0x34 /* PC Card Attribute Socket 1 Register */
-# define MCIO0 0x38 /* PC Card I/O Socket 0 Timing Register */
-# define MCIO1 0x3c /* PC Card I/O Socket 1 Timing Register */
-# define MDMRS 0x40 /* SDRAM Mode Register Set Config Register */
-# define BOOT_DEF 0x44 /* Boot-time Default Configuration Register */
-# define ARB_CNTL 0x48 /* Arbiter Control Register */
-# define BSCNTR0 0x4c /* Memory Buffer Strength Control Register 0 */
-# define BSCNTR1 0x50 /* Memory Buffer Strength Control Register 1 */
-# define LCDBSCNTR 0x54 /* LCD Buffer Strength Control Register */
-# define MDMRSLP 0x58 /* Low Power SDRAM Mode Set Config Register */
-# define BSCNTR2 0x5c /* Memory Buffer Strength Control Register 2 */
-# define BSCNTR3 0x60 /* Memory Buffer Strength Control Register 3 */
-# define SA1110 0x64 /* SA-1110 Memory Compatibility Register */
-
-static uint32_t pxa2xx_mm_read(void *opaque, target_phys_addr_t addr)
-{
- struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
- addr -= s->mm_base;
-
- switch (addr) {
- case MDCNFG ... SA1110:
- if ((addr & 3) == 0)
- return s->mm_regs[addr >> 2];
-
- default:
- printf("%s: Bad register 0x%lx\n", __FUNCTION__, addr);
- break;
- }
- return 0;
-}
-
-static void pxa2xx_mm_write(void *opaque, target_phys_addr_t addr,
- uint32_t value)
-{
- struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
- addr -= s->mm_base;
-
- switch (addr) {
- case MDCNFG ... SA1110:
- if ((addr & 3) == 0) {
- s->mm_regs[addr >> 2] = value;
- break;
- }
-
- default:
- printf("%s: Bad register 0x%lx\n", __FUNCTION__, addr);
- break;
- }
-}
-
-static CPUReadMemoryFunc *pxa2xx_mm_readfn[] = {
- pxa2xx_mm_read,
- pxa2xx_mm_read,
- pxa2xx_mm_read,
-};
-
-static CPUWriteMemoryFunc *pxa2xx_mm_writefn[] = {
- pxa2xx_mm_write,
- pxa2xx_mm_write,
- pxa2xx_mm_write,
-};
-
-/* Synchronous Serial Ports */
-struct pxa2xx_ssp_s {
- target_phys_addr_t base;
- int irq;
- struct pxa2xx_pic_state_s *pic;
- int enable;
-
- uint32_t sscr[2];
- uint32_t sspsp;
- uint32_t ssto;
- uint32_t ssitr;
- uint32_t sssr;
- uint8_t sstsa;
- uint8_t ssrsa;
- uint8_t ssacd;
-
- uint32_t rx_fifo[16];
- int rx_level;
- int rx_start;
-
- uint32_t (*readfn)(void *opaque);
- void (*writefn)(void *opaque, uint32_t value);
- void *opaque;
-};
-
-# define SSCR0 0x00 /* SSP Control Register 0 */
-# define SSCR1 0x04 /* SSP Control Register 1 */
-# define SSSR 0x08 /* SSP Status Register */
-# define SSITR 0x0c /* SSP Interrupt Test Register */
-# define SSDR 0x10 /* SSP Data Register */
-# define SSTO 0x28 /* SSP Time-Out Register */
-# define SSPSP 0x2c /* SSP Programmable Serial Protocol Register */
-# define SSTSA 0x30 /* SSP TX Time Slot Active Register */
-# define SSRSA 0x34 /* SSP RX Time Slot Active Register */
-# define SSTSS 0x38 /* SSP Time Slot Status Register */
-# define SSACD 0x3c /* SSP Audio Clock Divider Register */
-
-/* Bitfields for above registers */
-# define SSCR0_SPI(x) (((x) & 0x30) == 0x00)
-# define SSCR0_SSP(x) (((x) & 0x30) == 0x10)
-# define SSCR0_UWIRE(x) (((x) & 0x30) == 0x20)
-# define SSCR0_PSP(x) (((x) & 0x30) == 0x30)
-# define SSCR0_SSE (1 << 7)
-# define SSCR0_RIM (1 << 22)
-# define SSCR0_TIM (1 << 23)
-# define SSCR0_MOD (1 << 31)
-# define SSCR0_DSS(x) (((((x) >> 16) & 0x10) | ((x) & 0xf)) + 1)
-# define SSCR1_RIE (1 << 0)
-# define SSCR1_TIE (1 << 1)
-# define SSCR1_LBM (1 << 2)
-# define SSCR1_MWDS (1 << 5)
-# define SSCR1_TFT(x) ((((x) >> 6) & 0xf) + 1)
-# define SSCR1_RFT(x) ((((x) >> 10) & 0xf) + 1)
-# define SSCR1_EFWR (1 << 14)
-# define SSCR1_PINTE (1 << 18)
-# define SSCR1_TINTE (1 << 19)
-# define SSCR1_RSRE (1 << 20)
-# define SSCR1_TSRE (1 << 21)
-# define SSCR1_EBCEI (1 << 29)
-# define SSITR_INT (7 << 5)
-# define SSSR_TNF (1 << 2)
-# define SSSR_RNE (1 << 3)
-# define SSSR_TFS (1 << 5)
-# define SSSR_RFS (1 << 6)
-# define SSSR_ROR (1 << 7)
-# define SSSR_PINT (1 << 18)
-# define SSSR_TINT (1 << 19)
-# define SSSR_EOC (1 << 20)
-# define SSSR_TUR (1 << 21)
-# define SSSR_BCE (1 << 23)
-# define SSSR_RW 0x00bc0080
-
-static void pxa2xx_ssp_int_update(struct pxa2xx_ssp_s *s)
-{
- int level = 0;
-
- level |= s->ssitr & SSITR_INT;
- level |= (s->sssr & SSSR_BCE) && (s->sscr[1] & SSCR1_EBCEI);
- level |= (s->sssr & SSSR_TUR) && !(s->sscr[0] & SSCR0_TIM);
- level |= (s->sssr & SSSR_EOC) && (s->sssr & (SSSR_TINT | SSSR_PINT));
- level |= (s->sssr & SSSR_TINT) && (s->sscr[1] & SSCR1_TINTE);
- level |= (s->sssr & SSSR_PINT) && (s->sscr[1] & SSCR1_PINTE);
- level |= (s->sssr & SSSR_ROR) && !(s->sscr[0] & SSCR0_RIM);
- level |= (s->sssr & SSSR_RFS) && (s->sscr[1] & SSCR1_RIE);
- level |= (s->sssr & SSSR_TFS) && (s->sscr[1] & SSCR1_TIE);
- pic_set_irq_new(s->pic, s->irq, !!level);
-}
-
-static void pxa2xx_ssp_fifo_update(struct pxa2xx_ssp_s *s)
-{
- s->sssr &= ~(0xf << 12); /* Clear RFL */
- s->sssr &= ~(0xf << 8); /* Clear TFL */
- s->sssr &= ~SSSR_TNF;
- if (s->enable) {
- s->sssr |= ((s->rx_level - 1) & 0xf) << 12;
- if (s->rx_level >= SSCR1_RFT(s->sscr[1]))
- s->sssr |= SSSR_RFS;
- else
- s->sssr &= ~SSSR_RFS;
- if (0 <= SSCR1_TFT(s->sscr[1]))
- s->sssr |= SSSR_TFS;
- else
- s->sssr &= ~SSSR_TFS;
- if (s->rx_level)
- s->sssr |= SSSR_RNE;
- else
- s->sssr &= ~SSSR_RNE;
- s->sssr |= SSSR_TNF;
- }
-
- pxa2xx_ssp_int_update(s);
-}
-
-static uint32_t pxa2xx_ssp_read(void *opaque, target_phys_addr_t addr)
-{
- struct pxa2xx_ssp_s *s = (struct pxa2xx_ssp_s *) opaque;
- uint32_t retval;
- addr -= s->base;
-
- switch (addr) {
- case SSCR0:
- return s->sscr[0];
- case SSCR1:
- return s->sscr[1];
- case SSPSP:
- return s->sspsp;
- case SSTO:
- return s->ssto;
- case SSITR:
- return s->ssitr;
- case SSSR:
- return s->sssr | s->ssitr;
- case SSDR:
- if (!s->enable)
- return 0xffffffff;
- if (s->rx_level < 1) {
- printf("%s: SSP Rx Underrun\n", __FUNCTION__);
- return 0xffffffff;
- }
- s->rx_level --;
- retval = s->rx_fifo[s->rx_start ++];
- s->rx_start &= 0xf;
- pxa2xx_ssp_fifo_update(s);
- return retval;
- case SSTSA:
- return s->sstsa;
- case SSRSA:
- return s->ssrsa;
- case SSTSS:
- return 0;
- case SSACD:
- return s->ssacd;
- default:
- printf("%s: Bad register 0x%lx\n", __FUNCTION__, addr);
- break;
- }
- return 0;
-}
-
-static void pxa2xx_ssp_write(void *opaque, target_phys_addr_t addr,
- uint32_t value)
-{
- struct pxa2xx_ssp_s *s = (struct pxa2xx_ssp_s *) opaque;
- addr -= s->base;
-
- switch (addr) {
- case SSCR0:
- s->sscr[0] = value & 0xc7ffffff;
- s->enable = value & SSCR0_SSE;
- if (value & SSCR0_MOD)
- printf("%s: Attempt to use network mode\n", __FUNCTION__);
- if (s->enable && SSCR0_DSS(value) < 4)
- printf("%s: Wrong data size: %i bits\n", __FUNCTION__,
- SSCR0_DSS(value));
- if (!(value & SSCR0_SSE)) {
- s->sssr = 0;
- s->ssitr = 0;
- s->rx_level = 0;
- }
- pxa2xx_ssp_fifo_update(s);
- break;
-
- case SSCR1:
- s->sscr[1] = value;
- if (value & (SSCR1_LBM | SSCR1_EFWR))
- printf("%s: Attempt to use SSP test mode\n", __FUNCTION__);
- pxa2xx_ssp_fifo_update(s);
- break;
-
- case SSPSP:
- s->sspsp = value;
- break;
-
- case SSTO:
- s->ssto = value;
- break;
-
- case SSITR:
- s->ssitr = value & SSITR_INT;
- pxa2xx_ssp_int_update(s);
- break;
-
- case SSSR:
- s->sssr &= ~(value & SSSR_RW);
- pxa2xx_ssp_int_update(s);
- break;
-
- case SSDR:
- if (SSCR0_UWIRE(s->sscr[0])) {
- if (s->sscr[1] & SSCR1_MWDS)
- value &= 0xffff;
- else
- value &= 0xff;
- } else
- /* Note how 32bits overflow does no harm here */
- value &= (1 << SSCR0_DSS(s->sscr[0])) - 1;
-
- /* Data goes from here to the Tx FIFO and is shifted out from
- * there directly to the slave, no need to buffer it.
- */
- if (s->enable) {
- if (s->writefn)
- s->writefn(s->opaque, value);
-
- if (s->rx_level < 0x10) {
- if (s->readfn)
- s->rx_fifo[(s->rx_start + s->rx_level ++) & 0xf] =
- s->readfn(s->opaque);
- else
- s->rx_fifo[(s->rx_start + s->rx_level ++) & 0xf] = 0x0;
- } else
- s->sssr |= SSSR_ROR;
- }
- pxa2xx_ssp_fifo_update(s);
- break;
-
- case SSTSA:
- s->sstsa = value;
- break;
-
- case SSRSA:
- s->ssrsa = value;
- break;
-
- case SSACD:
- s->ssacd = value;
- break;
-
- default:
- printf("%s: Bad register 0x%lx\n", __FUNCTION__, addr);
- break;
- }
-}
-
-static inline void pxa2xx_ssp_attach(struct pxa2xx_ssp_s *port,
- uint32_t (*readfn)(void *opaque),
- void (*writefn)(void *opaque, uint32_t value), void *opaque)
-{
- if (!port) {
- printf("%s: no such SSP\n", __FUNCTION__);
- exit(-1);
- }
-
- port->opaque = opaque;
- port->readfn = readfn;
- port->writefn = writefn;
-}
-
-static CPUReadMemoryFunc *pxa2xx_ssp_readfn[] = {
- pxa2xx_ssp_read,
- pxa2xx_ssp_read,
- pxa2xx_ssp_read,
-};
-
-static CPUWriteMemoryFunc *pxa2xx_ssp_writefn[] = {
- pxa2xx_ssp_write,
- pxa2xx_ssp_write,
- pxa2xx_ssp_write,
-};
-
-# define RCNR 0x00 /* RTC Counter Register */
-# define RTAR 0x04 /* RTC Alarm Register */
-# define RTSR 0x08 /* RTC Status Register */
-# define RTTR 0x0c /* RTC Timer Trim Register */
-# define RDCR 0x10 /* RTC Day Counter Register */
-# define RYCR 0x14 /* RTC Year Counter Register */
-# define RDAR1 0x18 /* RTC Wristwatch Day Alarm Register 1 */
-# define RYAR1 0x1c /* RTC Wristwatch Year Alarm Register 1 */
-# define RDAR2 0x20 /* RTC Wristwatch Day Alarm Register 2 */
-# define RYAR2 0x24 /* RTC Wristwatch Year Alarm Register 2 */
-# define SWCR 0x28 /* RTC Stopwatch Counter Register */
-# define SWAR1 0x2c /* RTC Stopwatch Alarm Register 1 */
-# define SWAR2 0x30 /* RTC Stopwatch Alarm Register 2 */
-# define RTCPICR 0x34 /* RTC Periodic Interrupt Counter Register */
-# define PIAR 0x38 /* RTC Periodic Interrupt Alarm Register */
-
-static inline void pxa2xx_rtc_int_update(struct pxa2xx_state_s *s)
-{
- pic_set_irq_new(s->pic, PXA2XX_PIC_RTCALARM, !!(s->rtsr & 0x2553));
-}
-
-static void pxa2xx_rtc_hzupdate(struct pxa2xx_state_s *s)
-{
- int64_t rt = qemu_get_clock(rt_clock);
- s->last_rcnr += ((rt - s->last_hz) << 15) /
- (1000 * ((s->rttr & 0xffff) + 1));
- s->last_rdcr += ((rt - s->last_hz) << 15) /
- (1000 * ((s->rttr & 0xffff) + 1));
- s->last_hz = rt;
-}
-
-static void pxa2xx_rtc_swupdate(struct pxa2xx_state_s *s)
-{
- int64_t rt = qemu_get_clock(rt_clock);
- if (s->rtsr & (1 << 12))
- s->last_swcr += (rt - s->last_sw) / 10;
- s->last_sw = rt;
-}
-
-static void pxa2xx_rtc_piupdate(struct pxa2xx_state_s *s)
-{
- int64_t rt = qemu_get_clock(rt_clock);
- if (s->rtsr & (1 << 15))
- s->last_swcr += rt - s->last_pi;
- s->last_pi = rt;
-}
-
-static inline void pxa2xx_rtc_alarm_update(struct pxa2xx_state_s *s,
- uint32_t rtsr)
-{
- if ((rtsr & (1 << 2)) && !(rtsr & (1 << 0)))
- qemu_mod_timer(s->rtc_hz, s->last_hz +
- (((s->rtar - s->last_rcnr) * 1000 *
- ((s->rttr & 0xffff) + 1)) >> 15));
- else
- qemu_del_timer(s->rtc_hz);
-
- if ((rtsr & (1 << 5)) && !(rtsr & (1 << 4)))
- qemu_mod_timer(s->rtc_rdal1, s->last_hz +
- (((s->rdar1 - s->last_rdcr) * 1000 *
- ((s->rttr & 0xffff) + 1)) >> 15)); /* TODO: fixup */
- else
- qemu_del_timer(s->rtc_rdal1);
-
- if ((rtsr & (1 << 7)) && !(rtsr & (1 << 6)))
- qemu_mod_timer(s->rtc_rdal2, s->last_hz +
- (((s->rdar2 - s->last_rdcr) * 1000 *
- ((s->rttr & 0xffff) + 1)) >> 15)); /* TODO: fixup */
- else
- qemu_del_timer(s->rtc_rdal2);
-
- if ((rtsr & 0x1200) == 0x1200 && !(rtsr & (1 << 8)))
- qemu_mod_timer(s->rtc_swal1, s->last_sw +
- (s->swar1 - s->last_swcr) * 10); /* TODO: fixup */
- else
- qemu_del_timer(s->rtc_swal1);
-
- if ((rtsr & 0x1800) == 0x1800 && !(rtsr & (1 << 10)))
- qemu_mod_timer(s->rtc_swal2, s->last_sw +
- (s->swar2 - s->last_swcr) * 10); /* TODO: fixup */
- else
- qemu_del_timer(s->rtc_swal2);
-
- if ((rtsr & 0xc000) == 0xc000 && !(rtsr & (1 << 13)))
- qemu_mod_timer(s->rtc_pi, s->last_pi +
- (s->piar & 0xffff) - s->last_rtcpicr);
- else
- qemu_del_timer(s->rtc_pi);
-}
-
-static inline void pxa2xx_rtc_hz_tick(void *opaque)
-{
- struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
- s->rtsr |= (1 << 0);
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- pxa2xx_rtc_int_update(s);
-}
-
-static inline void pxa2xx_rtc_rdal1_tick(void *opaque)
-{
- struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
- s->rtsr |= (1 << 4);
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- pxa2xx_rtc_int_update(s);
-}
-
-static inline void pxa2xx_rtc_rdal2_tick(void *opaque)
-{
- struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
- s->rtsr |= (1 << 6);
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- pxa2xx_rtc_int_update(s);
-}
-
-static inline void pxa2xx_rtc_swal1_tick(void *opaque)
-{
- struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
- s->rtsr |= (1 << 8);
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- pxa2xx_rtc_int_update(s);
-}
-
-static inline void pxa2xx_rtc_swal2_tick(void *opaque)
-{
- struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
- s->rtsr |= (1 << 10);
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- pxa2xx_rtc_int_update(s);
-}
-
-static inline void pxa2xx_rtc_pi_tick(void *opaque)
-{
- struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
- s->rtsr |= (1 << 13);
- pxa2xx_rtc_piupdate(s);
- s->last_rtcpicr = 0;
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- pxa2xx_rtc_int_update(s);
-}
-
-static uint32_t pxa2xx_rtc_read(void *opaque, target_phys_addr_t addr)
-{
- struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
- addr -= s->rtc_base;
-
- switch (addr) {
- case RTTR:
- return s->rttr;
- case RTSR:
- return s->rtsr;
- case RTAR:
- return s->rtar;
- case RDAR1:
- return s->rdar1;
- case RDAR2:
- return s->rdar2;
- case RYAR1:
- return s->ryar1;
- case RYAR2:
- return s->ryar2;
- case SWAR1:
- return s->swar1;
- case SWAR2:
- return s->swar2;
- case PIAR:
- return s->piar;
- case RCNR:
- return s->last_rcnr + ((qemu_get_clock(rt_clock) - s->last_hz) << 15) /
- (1000 * ((s->rttr & 0xffff) + 1));
- case RDCR:
- return s->last_rdcr + ((qemu_get_clock(rt_clock) - s->last_hz) << 15) /
- (1000 * ((s->rttr & 0xffff) + 1));
- case RYCR:
- return s->last_rycr;
- case SWCR:
- if (s->rtsr & (1 << 12))
- return s->last_swcr + (qemu_get_clock(rt_clock) - s->last_sw) / 10;
- else
- return s->last_swcr;
- default:
- printf("%s: Bad register 0x%lx\n", __FUNCTION__, addr);
- break;
- }
- return 0;
-}
-
-static void pxa2xx_rtc_write(void *opaque, target_phys_addr_t addr,
- uint32_t value)
-{
- struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
- addr -= s->rtc_base;
-
- switch (addr) {
- case RTTR:
- if (!(s->rttr & (1 << 31))) {
- pxa2xx_rtc_hzupdate(s);
- s->rttr = value;
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- }
- break;
-
- case RTSR:
- if ((s->rtsr ^ value) & (1 << 15))
- pxa2xx_rtc_piupdate(s);
-
- if ((s->rtsr ^ value) & (1 << 12))
- pxa2xx_rtc_swupdate(s);
-
- if (((s->rtsr ^ value) & 0x4aac) | (value & ~0xdaac))
- pxa2xx_rtc_alarm_update(s, value);
-
- s->rtsr = (value & 0xdaac) | (s->rtsr & ~(value & ~0xdaac));
- pxa2xx_rtc_int_update(s);
- break;
-
- case RTAR:
- s->rtar = value;
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- break;
-
- case RDAR1:
- s->rdar1 = value;
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- break;
-
- case RDAR2:
- s->rdar2 = value;
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- break;
-
- case RYAR1:
- s->ryar1 = value;
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- break;
-
- case RYAR2:
- s->ryar2 = value;
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- break;
-
- case SWAR1:
- pxa2xx_rtc_swupdate(s);
- s->swar1 = value;
- s->last_swcr = 0;
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- break;
-
- case SWAR2:
- s->swar2 = value;
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- break;
-
- case PIAR:
- s->piar = value;
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- break;
-
- case RCNR:
- pxa2xx_rtc_hzupdate(s);
- s->last_rcnr = value;
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- break;
-
- case RDCR:
- pxa2xx_rtc_hzupdate(s);
- s->last_rdcr = value;
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- break;
-
- case RYCR:
- s->last_rycr = value;
- break;
-
- case SWCR:
- pxa2xx_rtc_swupdate(s);
- s->last_swcr = value;
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- break;
-
- case RTCPICR:
- pxa2xx_rtc_piupdate(s);
- s->last_rtcpicr = value & 0xffff;
- pxa2xx_rtc_alarm_update(s, s->rtsr);
- break;
-
- default:
- printf("%s: Bad register 0x%lx\n", __FUNCTION__, addr);
- }
-}
-
-static void pxa2xx_rtc_reset(struct pxa2xx_state_s *s)
-{
- struct tm *tm;
- time_t ti;
- int wom;
-
- s->rttr = 0x7fff;
- s->rtsr = 0;
-
- time(&ti);
- if (rtc_utc)
- tm = gmtime(&ti);
- else
- tm = localtime(&ti);
- wom = ((tm->tm_mday - 1) / 7) + 1;
-
- s->last_rcnr = (uint32_t) ti;
- s->last_rdcr = (wom << 20) | ((tm->tm_wday + 1) << 17) |
- (tm->tm_hour << 12) | (tm->tm_min << 6) | tm->tm_sec;
- s->last_rycr = ((tm->tm_year + 1900) << 9) |
- ((tm->tm_mon + 1) << 5) | tm->tm_mday;
- s->last_swcr = (tm->tm_hour << 19) |
- (tm->tm_min << 13) | (tm->tm_sec << 7);
- s->last_rtcpicr = 0;
- s->last_hz = s->last_sw = s->last_pi = qemu_get_clock(rt_clock);
-
- s->rtc_hz = qemu_new_timer(rt_clock, pxa2xx_rtc_hz_tick, s);
- s->rtc_rdal1 = qemu_new_timer(rt_clock, pxa2xx_rtc_rdal1_tick, s);
- s->rtc_rdal2 = qemu_new_timer(rt_clock, pxa2xx_rtc_rdal2_tick, s);
- s->rtc_swal1 = qemu_new_timer(rt_clock, pxa2xx_rtc_swal1_tick, s);
- s->rtc_swal2 = qemu_new_timer(rt_clock, pxa2xx_rtc_swal2_tick, s);
- s->rtc_pi = qemu_new_timer(rt_clock, pxa2xx_rtc_pi_tick, s);
-}
-
-static CPUReadMemoryFunc *pxa2xx_rtc_readfn[] = {
- pxa2xx_rtc_read,
- pxa2xx_rtc_read,
- pxa2xx_rtc_read,
-};
-
-static CPUWriteMemoryFunc *pxa2xx_rtc_writefn[] = {
- pxa2xx_rtc_write,
- pxa2xx_rtc_write,
- pxa2xx_rtc_write,
-};
-
-/* I2C Interface */
struct pxa2xx_i2c_s {
+ i2c_slave slave;
+ i2c_bus *bus;
target_phys_addr_t base;
- int irq;
- struct pxa2xx_pic_state_s *pic;
- struct i2c_master_s master;
- struct i2c_slave_s slave;
+ qemu_irq irq;
uint16_t control;
uint16_t status;
uint8_t ibmr;
+ uint8_t data;
};
-# define IBMR 0x80 /* I2C Bus Monitor Register */
-# define IDBR 0x88 /* I2C Data Buffer Register */
-# define ICR 0x90 /* I2C Control Register */
-# define ISR 0x98 /* I2C Status Register */
-# define ISAR 0xa0 /* I2C Slave Address Register */
-
-static void pxa2xx_i2c_update(struct pxa2xx_i2c_s *s)
-{
- uint16_t level = 0;
- level |= s->status & s->control & (1 << 10); /* BED */
- level |= (s->status & (1 << 7)) && (s->control & (1 << 9)); /* IRF */
- level |= (s->status & (1 << 6)) && (s->control & (1 << 8)); /* ITE */
- level |= s->status & (1 << 9); /* SAD */
- pic_set_irq_new(s->pic, s->irq, !!level);
-}
-
-static void pxa2xx_i2c_start(void *opaque, int dir)
-{
- struct pxa2xx_i2c_s *s = (struct pxa2xx_i2c_s *) opaque;
- s->status |= (1 << 9); /* set SAD */
- if (dir)
- s->status |= 1 << 0; /* set RWM */
- else
- s->status &= ~(1 << 0); /* clear RWM */
-}
-
-static void pxa2xx_i2c_stop(void *opaque)
-{
- struct pxa2xx_i2c_s *s = (struct pxa2xx_i2c_s *) opaque;
- s->status |= (1 << 4); /* set SSD */
-}
-
-static int pxa2xx_i2c_tx(void *opaque, uint8_t *message, int len)
-{
- struct pxa2xx_i2c_s *s = (struct pxa2xx_i2c_s *) opaque;
- if ((s->control & (1 << 14)) || !(s->control & (1 << 6)))
- return 1;
-
- if (len) {
- if (s->status & (1 << 0)) { /* RWM */
- s->status |= 1 << 6; /* set ITE */
- s->master.data = message[0]; /* TODO */
- } else {
- s->status |= 1 << 7; /* set IRF */
- message[0] = s->master.data; /* TODO */
- }
- }
- pxa2xx_i2c_update(s);
-
- return !s->master.ack;
-}
-
-static uint32_t pxa2xx_i2c_read(void *opaque, target_phys_addr_t addr)
-{
- struct pxa2xx_i2c_s *s = (struct pxa2xx_i2c_s *) opaque;
- addr -= s->base;
-
- switch (addr) {
- case ICR:
- return s->control;
- case ISR:
- return s->status;
- case ISAR:
- return s->slave.address;
- case IDBR:
- return s->master.data;
- case IBMR:
- if (s->status & (1 << 2))
- s->ibmr ^= 3; /* Fake SCL and SDA pin changes */
- else
- s->ibmr = 0;
- return s->ibmr;
- default:
- printf("%s: Bad register 0x%lx\n", __FUNCTION__, addr);
- break;
- }
- return 0;
-}
-
-static void pxa2xx_i2c_write(void *opaque, target_phys_addr_t addr,
- uint32_t value)
-{
- struct pxa2xx_i2c_s *s = (struct pxa2xx_i2c_s *) opaque;
- addr -= s->base;
-
- switch (addr) {
- case ICR:
- s->control = value & 0xfff7;
- if ((value & (1 << 3)) && (value & (1 << 6))) { /* TB and IUE */
- /* TODO: slave mode */
- if (value & (1 << 0)) { /* START condition */
- if (s->master.data & 1)
- s->status |= 1 << 0; /* set RWM */
- else
- s->status &= ~(1 << 0); /* clear RWM */
- s->status |= 1 << 2; /* set UB */
- }
-
- i2c_master_submit(&s->master,
- value & (1 << 0), /* START condition */
- value & (1 << 1)); /* STOP condition */
-
- if (s->master.ack) {
- if (s->status & (1 << 0)) /* RWM */
- s->status |= 1 << 7; /* set IRF */
- else
- s->status |= 1 << 6; /* set ITE */
- s->status &= ~(1 << 1); /* clear ACKNAK */
- } else {
- s->status |= 1 << 6; /* set ITE */
- s->status |= 1 << 10; /* set BED */
- s->status |= 1 << 1; /* set ACKNAK */
- s->status &= ~(1 << 2); /* clear UB */
- }
- if (value & (1 << 1)) /* STOP condition */
- s->status &= ~(1 << 2); /* clear UB */
- }
- if (value & (1 << 4)) /* MA */
- s->status &= ~(1 << 2); /* clear UB */
- if (!(value & (1 << 3)) && (value & (1 << 6))) /* !TB and IUE */
- s->status &= ~(1 << 2); /* clear UB */
- pxa2xx_i2c_update(s);
- break;
-
- case ISR:
- s->status &= ~(value & 0x07f0);
- pxa2xx_i2c_update(s);
- break;
-
- case ISAR:
- if (s->master.bus)
- i2c_slave_attach(s->master.bus, value & 0x7f, &s->slave);
- break;
-
- case IDBR:
- s->master.data = value & 0xff;
- break;
-
- default:
- printf("%s: Bad register 0x%lx\n", __FUNCTION__, addr);
- }
-}
-
-static CPUReadMemoryFunc *pxa2xx_i2c_readfn[] = {
- pxa2xx_i2c_read,
- pxa2xx_i2c_read,
- pxa2xx_i2c_read,
-};
-
-static CPUWriteMemoryFunc *pxa2xx_i2c_writefn[] = {
- pxa2xx_i2c_write,
- pxa2xx_i2c_write,
- pxa2xx_i2c_write,
-};
-
-static struct pxa2xx_i2c_s *pxa2xx_i2c_init(target_phys_addr_t base, int irq,
- struct pxa2xx_pic_state_s *pic)
-{
- int iomemtype;
- struct pxa2xx_i2c_s *s = (struct pxa2xx_i2c_s *)
- qemu_mallocz(sizeof(struct pxa2xx_i2c_s));
-
- s->base = base;
- s->irq = irq;
- s->pic = pic;
- s->slave.tx = pxa2xx_i2c_tx;
- s->slave.start = pxa2xx_i2c_start;
- s->slave.stop = pxa2xx_i2c_stop;
- s->slave.opaque = s;
-
- iomemtype = cpu_register_io_memory(0, pxa2xx_i2c_readfn,
- pxa2xx_i2c_writefn, s);
- cpu_register_physical_memory(s->base & 0xfffff000, 0xfff, iomemtype);
-
- return s;
-}
-
-/* PXA Inter-IC Sound Controller */
struct pxa2xx_i2s_s {
target_phys_addr_t base;
- int irq;
+ qemu_irq irq;
struct pxa2xx_dma_state_s *dma;
- struct pxa2xx_pic_state_s *pic;
void (*data_req)(void *, int, int);
uint32_t control[2];
@@ -1462,304 +211,13 @@
uint32_t fifo[16];
};
-static void pxa2xx_i2s_reset(struct pxa2xx_i2s_s *i2s)
-{
- i2s->rx_len = 0;
- i2s->tx_len = 0;
- i2s->fifo_len = 0;
- i2s->clk = 0x1a;
- i2s->control[0] = 0x00;
- i2s->control[1] = 0x00;
- i2s->status = 0x00;
- i2s->mask = 0x00;
-}
+# define PA_FMT "0x%08lx"
+# define REG_FMT "0x%lx"
-# define SACR_TFTH(val) ((val >> 8) & 0xf)
-# define SACR_RFTH(val) ((val >> 12) & 0xf)
-# define SACR_DREC(val) (val & (1 << 3))
-# define SACR_DPRL(val) (val & (1 << 4))
+struct pxa2xx_state_s *pxa270_init(unsigned int sdram_size, DisplayState *ds,
+ const char *revision);
+struct pxa2xx_state_s *pxa255_init(unsigned int sdram_size, DisplayState *ds);
-static inline void pxa2xx_i2s_update(struct pxa2xx_i2s_s *i2s)
-{
- int rfs, tfs;
- rfs = SACR_RFTH(i2s->control[0]) < i2s->rx_len &&
- !SACR_DREC(i2s->control[1]);
- tfs = (i2s->tx_len || i2s->fifo_len < SACR_TFTH(i2s->control[0])) &&
- i2s->enable && !SACR_DPRL(i2s->control[1]);
+void pxa2xx_reset(int line, int level, void *opaque);
- pxa2xx_dma_request(i2s->dma, PXA2XX_RX_RQ_I2S, rfs);
- pxa2xx_dma_request(i2s->dma, PXA2XX_TX_RQ_I2S, tfs);
-
- i2s->status &= 0xe0;
- if (i2s->rx_len)
- i2s->status |= 1 << 1; /* RNE */
- if (i2s->enable)
- i2s->status |= 1 << 2; /* BSY */
- if (tfs)
- i2s->status |= 1 << 3; /* TFS */
- if (rfs)
- i2s->status |= 1 << 4; /* RFS */
- if (!(i2s->tx_len && i2s->enable))
- i2s->status |= i2s->fifo_len << 8; /* TFL */
- i2s->status |= MAX(i2s->rx_len, 0xf) << 12; /* RFL */
-
- pic_set_irq_new(i2s->pic, i2s->irq, i2s->status & i2s->mask);
-}
-
-# define SACR0 0x00 /* Serial Audio Global Control Register */
-# define SACR1 0x04 /* Serial Audio I2S/MSB-Justified Control Register */
-# define SASR0 0x0c /* Serial Audio Interface and FIFO Status Register */
-# define SAIMR 0x14 /* Serial Audio Interrupt Mask Register */
-# define SAICR 0x18 /* Serial Audio Interrupt Clear Register */
-# define SADIV 0x60 /* Serial Audio Clock Divider Register */
-# define SADR 0x80 /* Serial Audio Data Register */
-
-static uint32_t pxa2xx_i2s_read(void *opaque, target_phys_addr_t addr)
-{
- struct pxa2xx_i2s_s *s = (struct pxa2xx_i2s_s *) opaque;
- addr -= s->base;
-
- switch (addr) {
- case SACR0:
- return s->control[0];
- case SACR1:
- return s->control[1];
- case SASR0:
- return s->status;
- case SAIMR:
- return s->mask;
- case SAICR:
- return 0;
- case SADIV:
- return s->clk;
- case SADR:
- if (s->rx_len > 0) {
- s->rx_len --;
- pxa2xx_i2s_update(s);
- return s->codec_in(s->opaque);
- }
- return 0;
- default:
- printf("%s: Bad register 0x%lx\n", __FUNCTION__, addr);
- break;
- }
- return 0;
-}
-
-static void pxa2xx_i2s_write(void *opaque, target_phys_addr_t addr,
- uint32_t value)
-{
- struct pxa2xx_i2s_s *s = (struct pxa2xx_i2s_s *) opaque;
- uint32_t *sample;
- addr -= s->base;
-
- switch (addr) {
- case SACR0:
- if (value & (1 << 3)) /* RST */
- pxa2xx_i2s_reset(s);
- s->control[0] = value & 0xff3d;
- if (!s->enable && (value & 1) && s->tx_len) { /* ENB */
- for (sample = s->fifo; s->fifo_len > 0; s->fifo_len --, sample ++)
- s->codec_out(s->opaque, *sample);
- s->status &= ~(1 << 7); /* I2SOFF */
- }
- if (value & (1 << 4)) /* EFWR */
- printf("%s: Attempt to use special function\n", __FUNCTION__);
- s->enable = ((value ^ 4) & 5) == 5; /* ENB && !RST*/
- pxa2xx_i2s_update(s);
- break;
- case SACR1:
- s->control[1] = value & 0x0039;
- if (value & (1 << 5)) /* ENLBF */
- printf("%s: Attempt to use loopback function\n", __FUNCTION__);
- if (value & (1 << 4)) /* DPRL */
- s->fifo_len = 0;
- pxa2xx_i2s_update(s);
- break;
- case SAIMR:
- s->mask = value & 0x0078;
- pxa2xx_i2s_update(s);
- break;
- case SAICR:
- s->status &= ~(value & (3 << 5));
- pxa2xx_i2s_update(s);
- break;
- case SADIV:
- s->clk = value & 0x007f;
- break;
- case SADR:
- if (s->tx_len && s->enable) {
- s->tx_len --;
- pxa2xx_i2s_update(s);
- s->codec_out(s->opaque, value);
- } else if (s->fifo_len < 16) {
- s->fifo[s->fifo_len ++] = value;
- pxa2xx_i2s_update(s);
- }
- break;
- default:
- printf("%s: Bad register 0x%lx\n", __FUNCTION__, addr);
- }
-}
-
-static CPUReadMemoryFunc *pxa2xx_i2s_readfn[] = {
- pxa2xx_i2s_read,
- pxa2xx_i2s_read,
- pxa2xx_i2s_read,
-};
-
-static CPUWriteMemoryFunc *pxa2xx_i2s_writefn[] = {
- pxa2xx_i2s_write,
- pxa2xx_i2s_write,
- pxa2xx_i2s_write,
-};
-
-static void pxa2xx_i2s_data_req(void *opaque, int tx, int rx)
-{
- struct pxa2xx_i2s_s *s = (struct pxa2xx_i2s_s *) opaque;
- uint32_t *sample;
-
- /* Signal FIFO errors */
- if (s->enable && s->tx_len)
- s->status |= 1 << 5; /* TUR */
- if (s->enable && s->rx_len)
- s->status |= 1 << 6; /* ROR */
-
- /* Should be tx - MIN(tx, s->fifo_len) but we don't really need to
- * handle the cases where it makes a difference. */
- s->tx_len = tx - s->fifo_len;
- s->rx_len = rx;
- /* Note that is s->codec_out wasn't set, we wouldn't get called. */
- if (s->enable)
- for (sample = s->fifo; s->fifo_len; s->fifo_len --, sample ++)
- s->codec_out(s->opaque, *sample);
- pxa2xx_i2s_update(s);
-}
-
-static struct pxa2xx_i2s_s *pxa2xx_i2s_init(target_phys_addr_t base, int irq,
- struct pxa2xx_pic_state_s *pic, struct pxa2xx_dma_state_s *dma)
-{
- int iomemtype;
- struct pxa2xx_i2s_s *s = (struct pxa2xx_i2s_s *)
- qemu_mallocz(sizeof(struct pxa2xx_i2s_s));
-
- s->base = base;
- s->irq = irq;
- s->pic = pic;
- s->dma = dma;
- s->data_req = pxa2xx_i2s_data_req;
-
- pxa2xx_i2s_reset(s);
-
- iomemtype = cpu_register_io_memory(0, pxa2xx_i2s_readfn,
- pxa2xx_i2s_writefn, s);
- cpu_register_physical_memory(s->base & 0xfff00000, 0xfffff, iomemtype);
-
- return s;
-}
-
-static void pxa2xx_reset(int line, int level, void *opaque)
-{
- struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
- if (level && (s->pm_regs[PCFR >> 2] & 0x10)) { /* GPR_EN */
- cpu_reset(s->env);
- /* TODO: reset peripherals */
- }
-}
-
-/* Initialise a PXA270 integrated chip (ARM based core). */
-static inline struct pxa2xx_state_s *pxa270_init(DisplayState *ds,
- int revision)
-{
- struct pxa2xx_state_s *s;
- struct pxa2xx_ssp_s *ssp;
- int iomemtype, i;
- s = (struct pxa2xx_state_s *) qemu_mallocz(sizeof(struct pxa2xx_state_s));
-
- s->env = cpu_init();
- cpu_arm_set_model(s->env, ARM_CPUID_PXA270 | revision);
-
- s->pic = pxa2xx_pic_init(0x40d00000, s->env,
- PXA2XX_PIC_CPU_IRQ, PXA2XX_PIC_CPU_FIQ);
-
- s->dma = pxa27x_dma_init(0x40000000, s->pic, PXA2XX_PIC_DMA);
-
- pxa27x_timer_init(0x40a00000, s->pic, PXA2XX_PIC_OST_0, s->env);
-
- s->gpio = pxa2xx_gpio_init(0x40e00000, s->env, s->pic, 121);
-
- s->mmc = pxa2xx_mmci_init(0x41100000, s->pic, s->dma);
-
- for (i = 0; pxa270_serial[i].io_base; i ++)
- if (serial_hds[i])
- serial_mm_init(*(arm_pic_handler *) s->pic, s->pic,
- pxa270_serial[i].io_base, 2,
- pxa270_serial[i].irq, serial_hds[i]);
-
- if (ds)
- s->lcd = pxa2xx_lcdc_init(0x44000000, s->pic, ds);
-
- s->cm_base = 0x41300000;
- s->cm_regs[CCCR >> 4] = 0x02000210; /* 416.0 MHz */
- s->clkcfg = 0x00000009; /* Turbo mode active */
- iomemtype = cpu_register_io_memory(0, pxa2xx_cm_readfn,
- pxa2xx_cm_writefn, s);
- cpu_register_physical_memory(s->cm_base, 0xfff, iomemtype);
-
- cpu_arm_set_cp_io(s->env, 14, pxa2xx_cp14_read, pxa2xx_cp14_write, s);
-
- s->mm_base = 0x48000000;
- s->mm_regs[MDMRS >> 2] = 0x00020002;
- s->mm_regs[MDREFR >> 2] = 0x03ca4000;
- s->mm_regs[MECR >> 2] = 0x00000001; /* Two PC Card sockets */
- iomemtype = cpu_register_io_memory(0, pxa2xx_mm_readfn,
- pxa2xx_mm_writefn, s);
- cpu_register_physical_memory(s->mm_base, 0xfff, iomemtype);
-
- for (i = 0; pxa27x_ssp[i].io_base; i ++);
- s->ssp = (struct pxa2xx_ssp_s **)
- qemu_mallocz(sizeof(struct pxa2xx_ssp_s *) * i);
- ssp = (struct pxa2xx_ssp_s *)
- qemu_mallocz(sizeof(struct pxa2xx_ssp_s) * i);
- for (i = 0; pxa27x_ssp[i].io_base; i ++) {
- s->ssp[i] = &ssp[i];
- ssp[i].base = pxa27x_ssp[i].io_base;
- ssp[i].irq = pxa27x_ssp[i].irq;
- ssp[i].pic = s->pic;
-
- iomemtype = cpu_register_io_memory(0, pxa2xx_ssp_readfn,
- pxa2xx_ssp_writefn, &ssp[i]);
- cpu_register_physical_memory(ssp[i].base, 0xfff, iomemtype);
- }
-
- if (usb_enabled) {
- usb_ohci_init_memio(0x4c000000, 3, -1, s->pic, PXA2XX_PIC_USBH1);
- }
-
- s->pcmcia[0] = pxa2xx_pcmcia_init(0x20000000);
- s->pcmcia[1] = pxa2xx_pcmcia_init(0x30000000);
-
- s->rtc_base = 0x40900000;
- iomemtype = cpu_register_io_memory(0, pxa2xx_rtc_readfn,
- pxa2xx_rtc_writefn, s);
- cpu_register_physical_memory(s->rtc_base, 0xfff, iomemtype);
- pxa2xx_rtc_reset(s);
-
- s->i2c[0] = pxa2xx_i2c_init(0x40301600, PXA2XX_PIC_I2C, s->pic);
- s->i2c[1] = pxa2xx_i2c_init(0x40f00100, PXA2XX_PIC_PWRI2C, s->pic);
-
- /* Register PM after PWRI2C to get the register mappings right. */
- s->pm_base = 0x40f00000;
- iomemtype = cpu_register_io_memory(0, pxa2xx_pm_readfn,
- pxa2xx_pm_writefn, s);
- cpu_register_physical_memory(s->pm_base, 0xfff, iomemtype);
-
- s->i2s = pxa2xx_i2s_init(0x40400000, PXA2XX_PIC_I2S, s->pic, s->dma);
-
- /* GPIO1 resets the processor */
- /* The handler can be overriden by board-specific code */
- pxa2xx_gpio_handler_set(s->gpio, 1, pxa2xx_reset, s);
- return s;
-}
-
#endif /* PXA_H */
Added: trunk/src/host/qemu-neo1973/hw/pxa2xx.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/pxa2xx.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/pxa2xx.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,1944 @@
+/*
+ * Intel XScale PXA255/270 processor support.
+ *
+ * Copyright (c) 2006 Openedhand Ltd.
+ * Written by Andrzej Zaborowski <balrog at zabor.org>
+ *
+ * This code is licenced under the GPL.
+ */
+
+# include "vl.h"
+
+static struct {
+ target_phys_addr_t io_base;
+ int irqn;
+} pxa255_serial[] = {
+ { 0x40100000, PXA2XX_PIC_FFUART },
+ { 0x40200000, PXA2XX_PIC_BTUART },
+ { 0x40700000, PXA2XX_PIC_STUART },
+ { 0x41600000, PXA25X_PIC_HWUART },
+ { 0, 0 }
+}, pxa270_serial[] = {
+ { 0x40100000, PXA2XX_PIC_FFUART },
+ { 0x40200000, PXA2XX_PIC_BTUART },
+ { 0x40700000, PXA2XX_PIC_STUART },
+ { 0, 0 }
+};
+
+static struct {
+ target_phys_addr_t io_base;
+ int irqn;
+} pxa250_ssp[] = {
+ { 0x41000000, PXA2XX_PIC_SSP },
+ { 0, 0 }
+}, pxa255_ssp[] = {
+ { 0x41000000, PXA2XX_PIC_SSP },
+ { 0x41400000, PXA25X_PIC_NSSP },
+ { 0, 0 }
+}, pxa26x_ssp[] = {
+ { 0x41000000, PXA2XX_PIC_SSP },
+ { 0x41400000, PXA25X_PIC_NSSP },
+ { 0x41500000, PXA26X_PIC_ASSP },
+ { 0, 0 }
+}, pxa27x_ssp[] = {
+ { 0x41000000, PXA2XX_PIC_SSP },
+ { 0x41700000, PXA27X_PIC_SSP2 },
+ { 0x41900000, PXA2XX_PIC_SSP3 },
+ { 0, 0 }
+};
+
+#define PMCR 0x00 /* Power Manager Control register */
+#define PSSR 0x04 /* Power Manager Sleep Status register */
+#define PSPR 0x08 /* Power Manager Scratch-Pad register */
+#define PWER 0x0c /* Power Manager Wake-Up Enable register */
+#define PRER 0x10 /* Power Manager Rising-Edge Detect Enable register */
+#define PFER 0x14 /* Power Manager Falling-Edge Detect Enable register */
+#define PEDR 0x18 /* Power Manager Edge-Detect Status register */
+#define PCFR 0x1c /* Power Manager General Configuration register */
+#define PGSR0 0x20 /* Power Manager GPIO Sleep-State register 0 */
+#define PGSR1 0x24 /* Power Manager GPIO Sleep-State register 1 */
+#define PGSR2 0x28 /* Power Manager GPIO Sleep-State register 2 */
+#define PGSR3 0x2c /* Power Manager GPIO Sleep-State register 3 */
+#define RCSR 0x30 /* Reset Controller Status register */
+#define PSLR 0x34 /* Power Manager Sleep Configuration register */
+#define PTSR 0x38 /* Power Manager Standby Configuration register */
+#define PVCR 0x40 /* Power Manager Voltage Change Control register */
+#define PUCR 0x4c /* Power Manager USIM Card Control/Status register */
+#define PKWR 0x50 /* Power Manager Keyboard Wake-Up Enable register */
+#define PKSR 0x54 /* Power Manager Keyboard Level-Detect Status */
+#define PCMD0 0x80 /* Power Manager I2C Command register File 0 */
+#define PCMD31 0xfc /* Power Manager I2C Command register File 31 */
+
+static uint32_t pxa2xx_i2c_read(void *, target_phys_addr_t);
+static void pxa2xx_i2c_write(void *, target_phys_addr_t, uint32_t);
+
+static uint32_t pxa2xx_pm_read(void *opaque, target_phys_addr_t addr)
+{
+ struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+ if (addr > s->pm_base + PCMD31) {
+ /* Special case: PWRI2C registers appear in the same range. */
+ return pxa2xx_i2c_read(s->i2c[1], addr);
+ }
+ addr -= s->pm_base;
+
+ switch (addr) {
+ case PMCR ... PCMD31:
+ if (addr & 3)
+ goto fail;
+
+ return s->pm_regs[addr >> 2];
+ default:
+ fail:
+ printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+ break;
+ }
+ return 0;
+}
+
+static void pxa2xx_pm_write(void *opaque, target_phys_addr_t addr,
+ uint32_t value)
+{
+ struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+ if (addr > s->pm_base + PCMD31) {
+ /* Special case: PWRI2C registers appear in the same range. */
+ pxa2xx_i2c_write(s->i2c[1], addr, value);
+ return;
+ }
+ addr -= s->pm_base;
+
+ switch (addr) {
+ case PMCR:
+ s->pm_regs[addr >> 2] &= 0x15 & ~(value & 0x2a);
+ s->pm_regs[addr >> 2] |= value & 0x15;
+ break;
+
+ case PSSR: /* Read-clean registers */
+ case RCSR:
+ case PKSR:
+ s->pm_regs[addr >> 2] &= ~value;
+ break;
+
+ default: /* Read-write registers */
+ if (addr >= PMCR && addr <= PCMD31 && !(addr & 3)) {
+ s->pm_regs[addr >> 2] = value;
+ break;
+ }
+
+ printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+ break;
+ }
+}
+
+static CPUReadMemoryFunc *pxa2xx_pm_readfn[] = {
+ pxa2xx_pm_read,
+ pxa2xx_pm_read,
+ pxa2xx_pm_read,
+};
+
+static CPUWriteMemoryFunc *pxa2xx_pm_writefn[] = {
+ pxa2xx_pm_write,
+ pxa2xx_pm_write,
+ pxa2xx_pm_write,
+};
+
+#define CCCR 0x00 /* Core Clock Configuration register */
+#define CKEN 0x04 /* Clock Enable register */
+#define OSCC 0x08 /* Oscillator Configuration register */
+#define CCSR 0x0c /* Core Clock Status register */
+
+static uint32_t pxa2xx_cm_read(void *opaque, target_phys_addr_t addr)
+{
+ struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+ addr -= s->cm_base;
+
+ switch (addr) {
+ case CCCR:
+ case CKEN:
+ case OSCC:
+ return s->cm_regs[addr >> 2];
+
+ case CCSR:
+ return s->cm_regs[CCCR >> 2] | (3 << 28);
+
+ default:
+ printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+ break;
+ }
+ return 0;
+}
+
+static void pxa2xx_cm_write(void *opaque, target_phys_addr_t addr,
+ uint32_t value)
+{
+ struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+ addr -= s->cm_base;
+
+ switch (addr) {
+ case CCCR:
+ case CKEN:
+ s->cm_regs[addr >> 2] = value;
+ break;
+
+ case OSCC:
+ s->cm_regs[addr >> 2] &= ~0x6c;
+ s->cm_regs[addr >> 2] |= value & 0x6e;
+ if ((value >> 1) & 1) /* OON */
+ s->cm_regs[addr >> 2] |= 1 << 0; /* Oscillator is now stable */
+ break;
+
+ default:
+ printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+ break;
+ }
+}
+
+static CPUReadMemoryFunc *pxa2xx_cm_readfn[] = {
+ pxa2xx_cm_read,
+ pxa2xx_cm_read,
+ pxa2xx_cm_read,
+};
+
+static CPUWriteMemoryFunc *pxa2xx_cm_writefn[] = {
+ pxa2xx_cm_write,
+ pxa2xx_cm_write,
+ pxa2xx_cm_write,
+};
+
+static uint32_t pxa2xx_clkpwr_read(void *opaque, int op2, int reg, int crm)
+{
+ struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+
+ switch (reg) {
+ case 6: /* Clock Configuration register */
+ return s->clkcfg;
+
+ case 7: /* Power Mode register */
+ return 0;
+
+ default:
+ printf("%s: Bad register 0x%x\n", __FUNCTION__, reg);
+ break;
+ }
+ return 0;
+}
+
+static void pxa2xx_clkpwr_write(void *opaque, int op2, int reg, int crm,
+ uint32_t value)
+{
+ struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+ static const char *pwrmode[8] = {
+ "Normal", "Idle", "Deep-idle", "Standby",
+ "Sleep", "reserved (!)", "reserved (!)", "Deep-sleep",
+ };
+
+ switch (reg) {
+ case 6: /* Clock Configuration register */
+ s->clkcfg = value & 0xf;
+ if (value & 2)
+ printf("%s: CPU frequency change attempt\n", __FUNCTION__);
+ break;
+
+ case 7: /* Power Mode register */
+ if (value & 8)
+ printf("%s: CPU voltage change attempt\n", __FUNCTION__);
+ switch (value & 7) {
+ case 0:
+ /* Do nothing */
+ break;
+
+ case 1:
+ /* Idle */
+ if (!(s->cm_regs[CCCR] & (1 << 31))) { /* CPDIS */
+ cpu_interrupt(s->env, CPU_INTERRUPT_HALT);
+ break;
+ }
+ /* Fall through. */
+
+ case 2:
+ /* Deep-Idle */
+ cpu_interrupt(s->env, CPU_INTERRUPT_HALT);
+ s->pm_regs[RCSR >> 2] |= 0x8; /* Set GPR */
+ goto message;
+
+ case 3:
+ s->env->uncached_cpsr =
+ ARM_CPU_MODE_SVC | CPSR_A | CPSR_F | CPSR_I;
+ s->env->cp15.c1_sys = 0;
+ s->env->cp15.c1_coproc = 0;
+ s->env->cp15.c2_base = 0;
+ s->env->cp15.c3 = 0;
+ s->pm_regs[PSSR >> 2] |= 0x8; /* Set STS */
+ s->pm_regs[RCSR >> 2] |= 0x8; /* Set GPR */
+
+ /*
+ * The scratch-pad register is almost universally used
+ * for storing the return address on suspend. For the
+ * lack of a resuming bootloader, perform a jump
+ * directly to that address.
+ */
+ memset(s->env->regs, 0, 4 * 15);
+ s->env->regs[15] = s->pm_regs[PSPR >> 2];
+
+#if 0
+ buffer = 0xe59ff000; /* ldr pc, [pc, #0] */
+ cpu_physical_memory_write(0, &buffer, 4);
+ buffer = s->pm_regs[PSPR >> 2];
+ cpu_physical_memory_write(8, &buffer, 4);
+#endif
+
+ /* Suspend */
+ cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HALT);
+
+ goto message;
+
+ default:
+ message:
+ printf("%s: machine entered %s mode\n", __FUNCTION__,
+ pwrmode[value & 7]);
+ }
+ break;
+
+ default:
+ printf("%s: Bad register 0x%x\n", __FUNCTION__, reg);
+ break;
+ }
+}
+
+/* Performace Monitoring Registers */
+#define CPPMNC 0 /* Performance Monitor Control register */
+#define CPCCNT 1 /* Clock Counter register */
+#define CPINTEN 4 /* Interrupt Enable register */
+#define CPFLAG 5 /* Overflow Flag register */
+#define CPEVTSEL 8 /* Event Selection register */
+
+#define CPPMN0 0 /* Performance Count register 0 */
+#define CPPMN1 1 /* Performance Count register 1 */
+#define CPPMN2 2 /* Performance Count register 2 */
+#define CPPMN3 3 /* Performance Count register 3 */
+
+static uint32_t pxa2xx_perf_read(void *opaque, int op2, int reg, int crm)
+{
+ struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+
+ switch (reg) {
+ case CPPMNC:
+ return s->pmnc;
+ case CPCCNT:
+ if (s->pmnc & 1)
+ return qemu_get_clock(vm_clock);
+ else
+ return 0;
+ case CPINTEN:
+ case CPFLAG:
+ case CPEVTSEL:
+ return 0;
+
+ default:
+ printf("%s: Bad register 0x%x\n", __FUNCTION__, reg);
+ break;
+ }
+ return 0;
+}
+
+static void pxa2xx_perf_write(void *opaque, int op2, int reg, int crm,
+ uint32_t value)
+{
+ struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+
+ switch (reg) {
+ case CPPMNC:
+ s->pmnc = value;
+ break;
+
+ case CPCCNT:
+ case CPINTEN:
+ case CPFLAG:
+ case CPEVTSEL:
+ break;
+
+ default:
+ printf("%s: Bad register 0x%x\n", __FUNCTION__, reg);
+ break;
+ }
+}
+
+static uint32_t pxa2xx_cp14_read(void *opaque, int op2, int reg, int crm)
+{
+ switch (crm) {
+ case 0:
+ return pxa2xx_clkpwr_read(opaque, op2, reg, crm);
+ case 1:
+ return pxa2xx_perf_read(opaque, op2, reg, crm);
+ case 2:
+ switch (reg) {
+ case CPPMN0:
+ case CPPMN1:
+ case CPPMN2:
+ case CPPMN3:
+ return 0;
+ }
+ /* Fall through */
+ default:
+ printf("%s: Bad register 0x%x\n", __FUNCTION__, reg);
+ break;
+ }
+ return 0;
+}
+
+static void pxa2xx_cp14_write(void *opaque, int op2, int reg, int crm,
+ uint32_t value)
+{
+ switch (crm) {
+ case 0:
+ pxa2xx_clkpwr_write(opaque, op2, reg, crm, value);
+ break;
+ case 1:
+ pxa2xx_perf_write(opaque, op2, reg, crm, value);
+ break;
+ case 2:
+ switch (reg) {
+ case CPPMN0:
+ case CPPMN1:
+ case CPPMN2:
+ case CPPMN3:
+ return;
+ }
+ /* Fall through */
+ default:
+ printf("%s: Bad register 0x%x\n", __FUNCTION__, reg);
+ break;
+ }
+}
+
+#define MDCNFG 0x00 /* SDRAM Configuration register */
+#define MDREFR 0x04 /* SDRAM Refresh Control register */
+#define MSC0 0x08 /* Static Memory Control register 0 */
+#define MSC1 0x0c /* Static Memory Control register 1 */
+#define MSC2 0x10 /* Static Memory Control register 2 */
+#define MECR 0x14 /* Expansion Memory Bus Config register */
+#define SXCNFG 0x1c /* Synchronous Static Memory Config register */
+#define MCMEM0 0x28 /* PC Card Memory Socket 0 Timing register */
+#define MCMEM1 0x2c /* PC Card Memory Socket 1 Timing register */
+#define MCATT0 0x30 /* PC Card Attribute Socket 0 register */
+#define MCATT1 0x34 /* PC Card Attribute Socket 1 register */
+#define MCIO0 0x38 /* PC Card I/O Socket 0 Timing register */
+#define MCIO1 0x3c /* PC Card I/O Socket 1 Timing register */
+#define MDMRS 0x40 /* SDRAM Mode Register Set Config register */
+#define BOOT_DEF 0x44 /* Boot-time Default Configuration register */
+#define ARB_CNTL 0x48 /* Arbiter Control register */
+#define BSCNTR0 0x4c /* Memory Buffer Strength Control register 0 */
+#define BSCNTR1 0x50 /* Memory Buffer Strength Control register 1 */
+#define LCDBSCNTR 0x54 /* LCD Buffer Strength Control register */
+#define MDMRSLP 0x58 /* Low Power SDRAM Mode Set Config register */
+#define BSCNTR2 0x5c /* Memory Buffer Strength Control register 2 */
+#define BSCNTR3 0x60 /* Memory Buffer Strength Control register 3 */
+#define SA1110 0x64 /* SA-1110 Memory Compatibility register */
+
+static uint32_t pxa2xx_mm_read(void *opaque, target_phys_addr_t addr)
+{
+ struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+ addr -= s->mm_base;
+
+ switch (addr) {
+ case MDCNFG ... SA1110:
+ if ((addr & 3) == 0)
+ return s->mm_regs[addr >> 2];
+
+ default:
+ printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+ break;
+ }
+ return 0;
+}
+
+static void pxa2xx_mm_write(void *opaque, target_phys_addr_t addr,
+ uint32_t value)
+{
+ struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+ addr -= s->mm_base;
+
+ switch (addr) {
+ case MDCNFG ... SA1110:
+ if ((addr & 3) == 0) {
+ s->mm_regs[addr >> 2] = value;
+ break;
+ }
+
+ default:
+ printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+ break;
+ }
+}
+
+static CPUReadMemoryFunc *pxa2xx_mm_readfn[] = {
+ pxa2xx_mm_read,
+ pxa2xx_mm_read,
+ pxa2xx_mm_read,
+};
+
+static CPUWriteMemoryFunc *pxa2xx_mm_writefn[] = {
+ pxa2xx_mm_write,
+ pxa2xx_mm_write,
+ pxa2xx_mm_write,
+};
+
+/* Synchronous Serial Ports */
+struct pxa2xx_ssp_s {
+ target_phys_addr_t base;
+ qemu_irq irq;
+ int enable;
+
+ uint32_t sscr[2];
+ uint32_t sspsp;
+ uint32_t ssto;
+ uint32_t ssitr;
+ uint32_t sssr;
+ uint8_t sstsa;
+ uint8_t ssrsa;
+ uint8_t ssacd;
+
+ uint32_t rx_fifo[16];
+ int rx_level;
+ int rx_start;
+
+ uint32_t (*readfn)(void *opaque);
+ void (*writefn)(void *opaque, uint32_t value);
+ void *opaque;
+};
+
+#define SSCR0 0x00 /* SSP Control register 0 */
+#define SSCR1 0x04 /* SSP Control register 1 */
+#define SSSR 0x08 /* SSP Status register */
+#define SSITR 0x0c /* SSP Interrupt Test register */
+#define SSDR 0x10 /* SSP Data register */
+#define SSTO 0x28 /* SSP Time-Out register */
+#define SSPSP 0x2c /* SSP Programmable Serial Protocol register */
+#define SSTSA 0x30 /* SSP TX Time Slot Active register */
+#define SSRSA 0x34 /* SSP RX Time Slot Active register */
+#define SSTSS 0x38 /* SSP Time Slot Status register */
+#define SSACD 0x3c /* SSP Audio Clock Divider register */
+
+/* Bitfields for above registers */
+#define SSCR0_SPI(x) (((x) & 0x30) == 0x00)
+#define SSCR0_SSP(x) (((x) & 0x30) == 0x10)
+#define SSCR0_UWIRE(x) (((x) & 0x30) == 0x20)
+#define SSCR0_PSP(x) (((x) & 0x30) == 0x30)
+#define SSCR0_SSE (1 << 7)
+#define SSCR0_RIM (1 << 22)
+#define SSCR0_TIM (1 << 23)
+#define SSCR0_MOD (1 << 31)
+#define SSCR0_DSS(x) (((((x) >> 16) & 0x10) | ((x) & 0xf)) + 1)
+#define SSCR1_RIE (1 << 0)
+#define SSCR1_TIE (1 << 1)
+#define SSCR1_LBM (1 << 2)
+#define SSCR1_MWDS (1 << 5)
+#define SSCR1_TFT(x) ((((x) >> 6) & 0xf) + 1)
+#define SSCR1_RFT(x) ((((x) >> 10) & 0xf) + 1)
+#define SSCR1_EFWR (1 << 14)
+#define SSCR1_PINTE (1 << 18)
+#define SSCR1_TINTE (1 << 19)
+#define SSCR1_RSRE (1 << 20)
+#define SSCR1_TSRE (1 << 21)
+#define SSCR1_EBCEI (1 << 29)
+#define SSITR_INT (7 << 5)
+#define SSSR_TNF (1 << 2)
+#define SSSR_RNE (1 << 3)
+#define SSSR_TFS (1 << 5)
+#define SSSR_RFS (1 << 6)
+#define SSSR_ROR (1 << 7)
+#define SSSR_PINT (1 << 18)
+#define SSSR_TINT (1 << 19)
+#define SSSR_EOC (1 << 20)
+#define SSSR_TUR (1 << 21)
+#define SSSR_BCE (1 << 23)
+#define SSSR_RW 0x00bc0080
+
+static void pxa2xx_ssp_int_update(struct pxa2xx_ssp_s *s)
+{
+ int level = 0;
+
+ level |= s->ssitr & SSITR_INT;
+ level |= (s->sssr & SSSR_BCE) && (s->sscr[1] & SSCR1_EBCEI);
+ level |= (s->sssr & SSSR_TUR) && !(s->sscr[0] & SSCR0_TIM);
+ level |= (s->sssr & SSSR_EOC) && (s->sssr & (SSSR_TINT | SSSR_PINT));
+ level |= (s->sssr & SSSR_TINT) && (s->sscr[1] & SSCR1_TINTE);
+ level |= (s->sssr & SSSR_PINT) && (s->sscr[1] & SSCR1_PINTE);
+ level |= (s->sssr & SSSR_ROR) && !(s->sscr[0] & SSCR0_RIM);
+ level |= (s->sssr & SSSR_RFS) && (s->sscr[1] & SSCR1_RIE);
+ level |= (s->sssr & SSSR_TFS) && (s->sscr[1] & SSCR1_TIE);
+ qemu_set_irq(s->irq, !!level);
+}
+
+static void pxa2xx_ssp_fifo_update(struct pxa2xx_ssp_s *s)
+{
+ s->sssr &= ~(0xf << 12); /* Clear RFL */
+ s->sssr &= ~(0xf << 8); /* Clear TFL */
+ s->sssr &= ~SSSR_TNF;
+ if (s->enable) {
+ s->sssr |= ((s->rx_level - 1) & 0xf) << 12;
+ if (s->rx_level >= SSCR1_RFT(s->sscr[1]))
+ s->sssr |= SSSR_RFS;
+ else
+ s->sssr &= ~SSSR_RFS;
+ if (0 <= SSCR1_TFT(s->sscr[1]))
+ s->sssr |= SSSR_TFS;
+ else
+ s->sssr &= ~SSSR_TFS;
+ if (s->rx_level)
+ s->sssr |= SSSR_RNE;
+ else
+ s->sssr &= ~SSSR_RNE;
+ s->sssr |= SSSR_TNF;
+ }
+
+ pxa2xx_ssp_int_update(s);
+}
+
+static uint32_t pxa2xx_ssp_read(void *opaque, target_phys_addr_t addr)
+{
+ struct pxa2xx_ssp_s *s = (struct pxa2xx_ssp_s *) opaque;
+ uint32_t retval;
+ addr -= s->base;
+
+ switch (addr) {
+ case SSCR0:
+ return s->sscr[0];
+ case SSCR1:
+ return s->sscr[1];
+ case SSPSP:
+ return s->sspsp;
+ case SSTO:
+ return s->ssto;
+ case SSITR:
+ return s->ssitr;
+ case SSSR:
+ return s->sssr | s->ssitr;
+ case SSDR:
+ if (!s->enable)
+ return 0xffffffff;
+ if (s->rx_level < 1) {
+ printf("%s: SSP Rx Underrun\n", __FUNCTION__);
+ return 0xffffffff;
+ }
+ s->rx_level --;
+ retval = s->rx_fifo[s->rx_start ++];
+ s->rx_start &= 0xf;
+ pxa2xx_ssp_fifo_update(s);
+ return retval;
+ case SSTSA:
+ return s->sstsa;
+ case SSRSA:
+ return s->ssrsa;
+ case SSTSS:
+ return 0;
+ case SSACD:
+ return s->ssacd;
+ default:
+ printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+ break;
+ }
+ return 0;
+}
+
+static void pxa2xx_ssp_write(void *opaque, target_phys_addr_t addr,
+ uint32_t value)
+{
+ struct pxa2xx_ssp_s *s = (struct pxa2xx_ssp_s *) opaque;
+ addr -= s->base;
+
+ switch (addr) {
+ case SSCR0:
+ s->sscr[0] = value & 0xc7ffffff;
+ s->enable = value & SSCR0_SSE;
+ if (value & SSCR0_MOD)
+ printf("%s: Attempt to use network mode\n", __FUNCTION__);
+ if (s->enable && SSCR0_DSS(value) < 4)
+ printf("%s: Wrong data size: %i bits\n", __FUNCTION__,
+ SSCR0_DSS(value));
+ if (!(value & SSCR0_SSE)) {
+ s->sssr = 0;
+ s->ssitr = 0;
+ s->rx_level = 0;
+ }
+ pxa2xx_ssp_fifo_update(s);
+ break;
+
+ case SSCR1:
+ s->sscr[1] = value;
+ if (value & (SSCR1_LBM | SSCR1_EFWR))
+ printf("%s: Attempt to use SSP test mode\n", __FUNCTION__);
+ pxa2xx_ssp_fifo_update(s);
+ break;
+
+ case SSPSP:
+ s->sspsp = value;
+ break;
+
+ case SSTO:
+ s->ssto = value;
+ break;
+
+ case SSITR:
+ s->ssitr = value & SSITR_INT;
+ pxa2xx_ssp_int_update(s);
+ break;
+
+ case SSSR:
+ s->sssr &= ~(value & SSSR_RW);
+ pxa2xx_ssp_int_update(s);
+ break;
+
+ case SSDR:
+ if (SSCR0_UWIRE(s->sscr[0])) {
+ if (s->sscr[1] & SSCR1_MWDS)
+ value &= 0xffff;
+ else
+ value &= 0xff;
+ } else
+ /* Note how 32bits overflow does no harm here */
+ value &= (1 << SSCR0_DSS(s->sscr[0])) - 1;
+
+ /* Data goes from here to the Tx FIFO and is shifted out from
+ * there directly to the slave, no need to buffer it.
+ */
+ if (s->enable) {
+ if (s->writefn)
+ s->writefn(s->opaque, value);
+
+ if (s->rx_level < 0x10) {
+ if (s->readfn)
+ s->rx_fifo[(s->rx_start + s->rx_level ++) & 0xf] =
+ s->readfn(s->opaque);
+ else
+ s->rx_fifo[(s->rx_start + s->rx_level ++) & 0xf] = 0x0;
+ } else
+ s->sssr |= SSSR_ROR;
+ }
+ pxa2xx_ssp_fifo_update(s);
+ break;
+
+ case SSTSA:
+ s->sstsa = value;
+ break;
+
+ case SSRSA:
+ s->ssrsa = value;
+ break;
+
+ case SSACD:
+ s->ssacd = value;
+ break;
+
+ default:
+ printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+ break;
+ }
+}
+
+void pxa2xx_ssp_attach(struct pxa2xx_ssp_s *port,
+ uint32_t (*readfn)(void *opaque),
+ void (*writefn)(void *opaque, uint32_t value), void *opaque)
+{
+ if (!port) {
+ printf("%s: no such SSP\n", __FUNCTION__);
+ exit(-1);
+ }
+
+ port->opaque = opaque;
+ port->readfn = readfn;
+ port->writefn = writefn;
+}
+
+static CPUReadMemoryFunc *pxa2xx_ssp_readfn[] = {
+ pxa2xx_ssp_read,
+ pxa2xx_ssp_read,
+ pxa2xx_ssp_read,
+};
+
+static CPUWriteMemoryFunc *pxa2xx_ssp_writefn[] = {
+ pxa2xx_ssp_write,
+ pxa2xx_ssp_write,
+ pxa2xx_ssp_write,
+};
+
+/* Real-Time Clock */
+#define RCNR 0x00 /* RTC Counter register */
+#define RTAR 0x04 /* RTC Alarm register */
+#define RTSR 0x08 /* RTC Status register */
+#define RTTR 0x0c /* RTC Timer Trim register */
+#define RDCR 0x10 /* RTC Day Counter register */
+#define RYCR 0x14 /* RTC Year Counter register */
+#define RDAR1 0x18 /* RTC Wristwatch Day Alarm register 1 */
+#define RYAR1 0x1c /* RTC Wristwatch Year Alarm register 1 */
+#define RDAR2 0x20 /* RTC Wristwatch Day Alarm register 2 */
+#define RYAR2 0x24 /* RTC Wristwatch Year Alarm register 2 */
+#define SWCR 0x28 /* RTC Stopwatch Counter register */
+#define SWAR1 0x2c /* RTC Stopwatch Alarm register 1 */
+#define SWAR2 0x30 /* RTC Stopwatch Alarm register 2 */
+#define RTCPICR 0x34 /* RTC Periodic Interrupt Counter register */
+#define PIAR 0x38 /* RTC Periodic Interrupt Alarm register */
+
+static inline void pxa2xx_rtc_int_update(struct pxa2xx_state_s *s)
+{
+ qemu_set_irq(s->pic[PXA2XX_PIC_RTCALARM], !!(s->rtsr & 0x2553));
+}
+
+static void pxa2xx_rtc_hzupdate(struct pxa2xx_state_s *s)
+{
+ int64_t rt = qemu_get_clock(rt_clock);
+ s->last_rcnr += ((rt - s->last_hz) << 15) /
+ (1000 * ((s->rttr & 0xffff) + 1));
+ s->last_rdcr += ((rt - s->last_hz) << 15) /
+ (1000 * ((s->rttr & 0xffff) + 1));
+ s->last_hz = rt;
+}
+
+static void pxa2xx_rtc_swupdate(struct pxa2xx_state_s *s)
+{
+ int64_t rt = qemu_get_clock(rt_clock);
+ if (s->rtsr & (1 << 12))
+ s->last_swcr += (rt - s->last_sw) / 10;
+ s->last_sw = rt;
+}
+
+static void pxa2xx_rtc_piupdate(struct pxa2xx_state_s *s)
+{
+ int64_t rt = qemu_get_clock(rt_clock);
+ if (s->rtsr & (1 << 15))
+ s->last_swcr += rt - s->last_pi;
+ s->last_pi = rt;
+}
+
+static inline void pxa2xx_rtc_alarm_update(struct pxa2xx_state_s *s,
+ uint32_t rtsr)
+{
+ if ((rtsr & (1 << 2)) && !(rtsr & (1 << 0)))
+ qemu_mod_timer(s->rtc_hz, s->last_hz +
+ (((s->rtar - s->last_rcnr) * 1000 *
+ ((s->rttr & 0xffff) + 1)) >> 15));
+ else
+ qemu_del_timer(s->rtc_hz);
+
+ if ((rtsr & (1 << 5)) && !(rtsr & (1 << 4)))
+ qemu_mod_timer(s->rtc_rdal1, s->last_hz +
+ (((s->rdar1 - s->last_rdcr) * 1000 *
+ ((s->rttr & 0xffff) + 1)) >> 15)); /* TODO: fixup */
+ else
+ qemu_del_timer(s->rtc_rdal1);
+
+ if ((rtsr & (1 << 7)) && !(rtsr & (1 << 6)))
+ qemu_mod_timer(s->rtc_rdal2, s->last_hz +
+ (((s->rdar2 - s->last_rdcr) * 1000 *
+ ((s->rttr & 0xffff) + 1)) >> 15)); /* TODO: fixup */
+ else
+ qemu_del_timer(s->rtc_rdal2);
+
+ if ((rtsr & 0x1200) == 0x1200 && !(rtsr & (1 << 8)))
+ qemu_mod_timer(s->rtc_swal1, s->last_sw +
+ (s->swar1 - s->last_swcr) * 10); /* TODO: fixup */
+ else
+ qemu_del_timer(s->rtc_swal1);
+
+ if ((rtsr & 0x1800) == 0x1800 && !(rtsr & (1 << 10)))
+ qemu_mod_timer(s->rtc_swal2, s->last_sw +
+ (s->swar2 - s->last_swcr) * 10); /* TODO: fixup */
+ else
+ qemu_del_timer(s->rtc_swal2);
+
+ if ((rtsr & 0xc000) == 0xc000 && !(rtsr & (1 << 13)))
+ qemu_mod_timer(s->rtc_pi, s->last_pi +
+ (s->piar & 0xffff) - s->last_rtcpicr);
+ else
+ qemu_del_timer(s->rtc_pi);
+}
+
+static inline void pxa2xx_rtc_hz_tick(void *opaque)
+{
+ struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+ s->rtsr |= (1 << 0);
+ pxa2xx_rtc_alarm_update(s, s->rtsr);
+ pxa2xx_rtc_int_update(s);
+}
+
+static inline void pxa2xx_rtc_rdal1_tick(void *opaque)
+{
+ struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+ s->rtsr |= (1 << 4);
+ pxa2xx_rtc_alarm_update(s, s->rtsr);
+ pxa2xx_rtc_int_update(s);
+}
+
+static inline void pxa2xx_rtc_rdal2_tick(void *opaque)
+{
+ struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+ s->rtsr |= (1 << 6);
+ pxa2xx_rtc_alarm_update(s, s->rtsr);
+ pxa2xx_rtc_int_update(s);
+}
+
+static inline void pxa2xx_rtc_swal1_tick(void *opaque)
+{
+ struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+ s->rtsr |= (1 << 8);
+ pxa2xx_rtc_alarm_update(s, s->rtsr);
+ pxa2xx_rtc_int_update(s);
+}
+
+static inline void pxa2xx_rtc_swal2_tick(void *opaque)
+{
+ struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+ s->rtsr |= (1 << 10);
+ pxa2xx_rtc_alarm_update(s, s->rtsr);
+ pxa2xx_rtc_int_update(s);
+}
+
+static inline void pxa2xx_rtc_pi_tick(void *opaque)
+{
+ struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+ s->rtsr |= (1 << 13);
+ pxa2xx_rtc_piupdate(s);
+ s->last_rtcpicr = 0;
+ pxa2xx_rtc_alarm_update(s, s->rtsr);
+ pxa2xx_rtc_int_update(s);
+}
+
+static uint32_t pxa2xx_rtc_read(void *opaque, target_phys_addr_t addr)
+{
+ struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+ addr -= s->rtc_base;
+
+ switch (addr) {
+ case RTTR:
+ return s->rttr;
+ case RTSR:
+ return s->rtsr;
+ case RTAR:
+ return s->rtar;
+ case RDAR1:
+ return s->rdar1;
+ case RDAR2:
+ return s->rdar2;
+ case RYAR1:
+ return s->ryar1;
+ case RYAR2:
+ return s->ryar2;
+ case SWAR1:
+ return s->swar1;
+ case SWAR2:
+ return s->swar2;
+ case PIAR:
+ return s->piar;
+ case RCNR:
+ return s->last_rcnr + ((qemu_get_clock(rt_clock) - s->last_hz) << 15) /
+ (1000 * ((s->rttr & 0xffff) + 1));
+ case RDCR:
+ return s->last_rdcr + ((qemu_get_clock(rt_clock) - s->last_hz) << 15) /
+ (1000 * ((s->rttr & 0xffff) + 1));
+ case RYCR:
+ return s->last_rycr;
+ case SWCR:
+ if (s->rtsr & (1 << 12))
+ return s->last_swcr + (qemu_get_clock(rt_clock) - s->last_sw) / 10;
+ else
+ return s->last_swcr;
+ default:
+ printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+ break;
+ }
+ return 0;
+}
+
+static void pxa2xx_rtc_write(void *opaque, target_phys_addr_t addr,
+ uint32_t value)
+{
+ struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+ addr -= s->rtc_base;
+
+ switch (addr) {
+ case RTTR:
+ if (!(s->rttr & (1 << 31))) {
+ pxa2xx_rtc_hzupdate(s);
+ s->rttr = value;
+ pxa2xx_rtc_alarm_update(s, s->rtsr);
+ }
+ break;
+
+ case RTSR:
+ if ((s->rtsr ^ value) & (1 << 15))
+ pxa2xx_rtc_piupdate(s);
+
+ if ((s->rtsr ^ value) & (1 << 12))
+ pxa2xx_rtc_swupdate(s);
+
+ if (((s->rtsr ^ value) & 0x4aac) | (value & ~0xdaac))
+ pxa2xx_rtc_alarm_update(s, value);
+
+ s->rtsr = (value & 0xdaac) | (s->rtsr & ~(value & ~0xdaac));
+ pxa2xx_rtc_int_update(s);
+ break;
+
+ case RTAR:
+ s->rtar = value;
+ pxa2xx_rtc_alarm_update(s, s->rtsr);
+ break;
+
+ case RDAR1:
+ s->rdar1 = value;
+ pxa2xx_rtc_alarm_update(s, s->rtsr);
+ break;
+
+ case RDAR2:
+ s->rdar2 = value;
+ pxa2xx_rtc_alarm_update(s, s->rtsr);
+ break;
+
+ case RYAR1:
+ s->ryar1 = value;
+ pxa2xx_rtc_alarm_update(s, s->rtsr);
+ break;
+
+ case RYAR2:
+ s->ryar2 = value;
+ pxa2xx_rtc_alarm_update(s, s->rtsr);
+ break;
+
+ case SWAR1:
+ pxa2xx_rtc_swupdate(s);
+ s->swar1 = value;
+ s->last_swcr = 0;
+ pxa2xx_rtc_alarm_update(s, s->rtsr);
+ break;
+
+ case SWAR2:
+ s->swar2 = value;
+ pxa2xx_rtc_alarm_update(s, s->rtsr);
+ break;
+
+ case PIAR:
+ s->piar = value;
+ pxa2xx_rtc_alarm_update(s, s->rtsr);
+ break;
+
+ case RCNR:
+ pxa2xx_rtc_hzupdate(s);
+ s->last_rcnr = value;
+ pxa2xx_rtc_alarm_update(s, s->rtsr);
+ break;
+
+ case RDCR:
+ pxa2xx_rtc_hzupdate(s);
+ s->last_rdcr = value;
+ pxa2xx_rtc_alarm_update(s, s->rtsr);
+ break;
+
+ case RYCR:
+ s->last_rycr = value;
+ break;
+
+ case SWCR:
+ pxa2xx_rtc_swupdate(s);
+ s->last_swcr = value;
+ pxa2xx_rtc_alarm_update(s, s->rtsr);
+ break;
+
+ case RTCPICR:
+ pxa2xx_rtc_piupdate(s);
+ s->last_rtcpicr = value & 0xffff;
+ pxa2xx_rtc_alarm_update(s, s->rtsr);
+ break;
+
+ default:
+ printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+ }
+}
+
+static void pxa2xx_rtc_reset(struct pxa2xx_state_s *s)
+{
+ struct tm *tm;
+ time_t ti;
+ int wom;
+
+ s->rttr = 0x7fff;
+ s->rtsr = 0;
+
+ time(&ti);
+ if (rtc_utc)
+ tm = gmtime(&ti);
+ else
+ tm = localtime(&ti);
+ wom = ((tm->tm_mday - 1) / 7) + 1;
+
+ s->last_rcnr = (uint32_t) ti;
+ s->last_rdcr = (wom << 20) | ((tm->tm_wday + 1) << 17) |
+ (tm->tm_hour << 12) | (tm->tm_min << 6) | tm->tm_sec;
+ s->last_rycr = ((tm->tm_year + 1900) << 9) |
+ ((tm->tm_mon + 1) << 5) | tm->tm_mday;
+ s->last_swcr = (tm->tm_hour << 19) |
+ (tm->tm_min << 13) | (tm->tm_sec << 7);
+ s->last_rtcpicr = 0;
+ s->last_hz = s->last_sw = s->last_pi = qemu_get_clock(rt_clock);
+
+ s->rtc_hz = qemu_new_timer(rt_clock, pxa2xx_rtc_hz_tick, s);
+ s->rtc_rdal1 = qemu_new_timer(rt_clock, pxa2xx_rtc_rdal1_tick, s);
+ s->rtc_rdal2 = qemu_new_timer(rt_clock, pxa2xx_rtc_rdal2_tick, s);
+ s->rtc_swal1 = qemu_new_timer(rt_clock, pxa2xx_rtc_swal1_tick, s);
+ s->rtc_swal2 = qemu_new_timer(rt_clock, pxa2xx_rtc_swal2_tick, s);
+ s->rtc_pi = qemu_new_timer(rt_clock, pxa2xx_rtc_pi_tick, s);
+}
+
+static CPUReadMemoryFunc *pxa2xx_rtc_readfn[] = {
+ pxa2xx_rtc_read,
+ pxa2xx_rtc_read,
+ pxa2xx_rtc_read,
+};
+
+static CPUWriteMemoryFunc *pxa2xx_rtc_writefn[] = {
+ pxa2xx_rtc_write,
+ pxa2xx_rtc_write,
+ pxa2xx_rtc_write,
+};
+
+/* I2C Interface */
+#define IBMR 0x80 /* I2C Bus Monitor register */
+#define IDBR 0x88 /* I2C Data Buffer register */
+#define ICR 0x90 /* I2C Control register */
+#define ISR 0x98 /* I2C Status register */
+#define ISAR 0xa0 /* I2C Slave Address register */
+
+static void pxa2xx_i2c_update(struct pxa2xx_i2c_s *s)
+{
+ uint16_t level = 0;
+ level |= s->status & s->control & (1 << 10); /* BED */
+ level |= (s->status & (1 << 7)) && (s->control & (1 << 9)); /* IRF */
+ level |= (s->status & (1 << 6)) && (s->control & (1 << 8)); /* ITE */
+ level |= s->status & (1 << 9); /* SAD */
+ qemu_set_irq(s->irq, !!level);
+}
+
+/* These are only stubs now. */
+static void pxa2xx_i2c_event(i2c_slave *i2c, enum i2c_event event)
+{
+ struct pxa2xx_i2c_s *s = (struct pxa2xx_i2c_s *) i2c;
+
+ switch (event) {
+ case I2C_START_SEND:
+ s->status |= (1 << 9); /* set SAD */
+ s->status &= ~(1 << 0); /* clear RWM */
+ break;
+ case I2C_START_RECV:
+ s->status |= (1 << 9); /* set SAD */
+ s->status |= 1 << 0; /* set RWM */
+ break;
+ case I2C_FINISH:
+ s->status |= (1 << 4); /* set SSD */
+ break;
+ case I2C_NACK:
+ s->status |= 1 << 1; /* set ACKNAK */
+ break;
+ }
+ pxa2xx_i2c_update(s);
+}
+
+static int pxa2xx_i2c_rx(i2c_slave *i2c)
+{
+ struct pxa2xx_i2c_s *s = (struct pxa2xx_i2c_s *) i2c;
+ if ((s->control & (1 << 14)) || !(s->control & (1 << 6)))
+ return 0;
+
+ if (s->status & (1 << 0)) { /* RWM */
+ s->status |= 1 << 6; /* set ITE */
+ }
+ pxa2xx_i2c_update(s);
+
+ return s->data;
+}
+
+static int pxa2xx_i2c_tx(i2c_slave *i2c, uint8_t data)
+{
+ struct pxa2xx_i2c_s *s = (struct pxa2xx_i2c_s *) i2c;
+ if ((s->control & (1 << 14)) || !(s->control & (1 << 6)))
+ return 1;
+
+ if (!(s->status & (1 << 0))) { /* RWM */
+ s->status |= 1 << 7; /* set IRF */
+ s->data = data;
+ }
+ pxa2xx_i2c_update(s);
+
+ return 1;
+}
+
+static uint32_t pxa2xx_i2c_read(void *opaque, target_phys_addr_t addr)
+{
+ struct pxa2xx_i2c_s *s = (struct pxa2xx_i2c_s *) opaque;
+ addr -= s->base;
+
+ switch (addr) {
+ case ICR:
+ return s->control;
+ case ISR:
+ return s->status | (i2c_bus_busy(s->bus) << 2);
+ case ISAR:
+ return s->slave.address;
+ case IDBR:
+ return s->data;
+ case IBMR:
+ if (s->status & (1 << 2))
+ s->ibmr ^= 3; /* Fake SCL and SDA pin changes */
+ else
+ s->ibmr = 0;
+ return s->ibmr;
+ default:
+ printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+ break;
+ }
+ return 0;
+}
+
+static void pxa2xx_i2c_write(void *opaque, target_phys_addr_t addr,
+ uint32_t value)
+{
+ struct pxa2xx_i2c_s *s = (struct pxa2xx_i2c_s *) opaque;
+ int ack;
+ addr -= s->base;
+
+ switch (addr) {
+ case ICR:
+ s->control = value & 0xfff7;
+ if ((value & (1 << 3)) && (value & (1 << 6))) { /* TB and IUE */
+ /* TODO: slave mode */
+ if (value & (1 << 0)) { /* START condition */
+ if (s->data & 1)
+ s->status |= 1 << 0; /* set RWM */
+ else
+ s->status &= ~(1 << 0); /* clear RWM */
+ ack = !i2c_start_transfer(s->bus, s->data >> 1, s->data & 1);
+ } else {
+ if (s->status & (1 << 0)) { /* RWM */
+ s->data = i2c_recv(s->bus);
+ if (value & (1 << 2)) /* ACKNAK */
+ i2c_nack(s->bus);
+ ack = 1;
+ } else
+ ack = !i2c_send(s->bus, s->data);
+ }
+
+ if (value & (1 << 1)) /* STOP condition */
+ i2c_end_transfer(s->bus);
+
+ if (ack) {
+ if (value & (1 << 0)) /* START condition */
+ s->status |= 1 << 6; /* set ITE */
+ else
+ if (s->status & (1 << 0)) /* RWM */
+ s->status |= 1 << 7; /* set IRF */
+ else
+ s->status |= 1 << 6; /* set ITE */
+ s->status &= ~(1 << 1); /* clear ACKNAK */
+ } else {
+ s->status |= 1 << 6; /* set ITE */
+ s->status |= 1 << 10; /* set BED */
+ s->status |= 1 << 1; /* set ACKNAK */
+ }
+ }
+ if (!(value & (1 << 3)) && (value & (1 << 6))) /* !TB and IUE */
+ if (value & (1 << 4)) /* MA */
+ i2c_end_transfer(s->bus);
+ pxa2xx_i2c_update(s);
+ break;
+
+ case ISR:
+ s->status &= ~(value & 0x07f0);
+ pxa2xx_i2c_update(s);
+ break;
+
+ case ISAR:
+ i2c_set_slave_address(&s->slave, value & 0x7f);
+ break;
+
+ case IDBR:
+ s->data = value & 0xff;
+ break;
+
+ default:
+ printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+ }
+}
+
+static CPUReadMemoryFunc *pxa2xx_i2c_readfn[] = {
+ pxa2xx_i2c_read,
+ pxa2xx_i2c_read,
+ pxa2xx_i2c_read,
+};
+
+static CPUWriteMemoryFunc *pxa2xx_i2c_writefn[] = {
+ pxa2xx_i2c_write,
+ pxa2xx_i2c_write,
+ pxa2xx_i2c_write,
+};
+
+static struct pxa2xx_i2c_s *pxa2xx_i2c_init(target_phys_addr_t base,
+ qemu_irq irq, int ioregister)
+{
+ int iomemtype;
+ struct pxa2xx_i2c_s *s = (struct pxa2xx_i2c_s *)
+ qemu_mallocz(sizeof(struct pxa2xx_i2c_s));
+
+ s->base = base;
+ s->irq = irq;
+ s->slave.event = pxa2xx_i2c_event;
+ s->slave.recv = pxa2xx_i2c_rx;
+ s->slave.send = pxa2xx_i2c_tx;
+ s->bus = i2c_init_bus();
+
+ if (ioregister) {
+ iomemtype = cpu_register_io_memory(0, pxa2xx_i2c_readfn,
+ pxa2xx_i2c_writefn, s);
+ cpu_register_physical_memory(s->base & 0xfffff000, 0xfff, iomemtype);
+ }
+
+ return s;
+}
+
+/* PXA Inter-IC Sound Controller */
+static void pxa2xx_i2s_reset(struct pxa2xx_i2s_s *i2s)
+{
+ i2s->rx_len = 0;
+ i2s->tx_len = 0;
+ i2s->fifo_len = 0;
+ i2s->clk = 0x1a;
+ i2s->control[0] = 0x00;
+ i2s->control[1] = 0x00;
+ i2s->status = 0x00;
+ i2s->mask = 0x00;
+}
+
+#define SACR_TFTH(val) ((val >> 8) & 0xf)
+#define SACR_RFTH(val) ((val >> 12) & 0xf)
+#define SACR_DREC(val) (val & (1 << 3))
+#define SACR_DPRL(val) (val & (1 << 4))
+
+static inline void pxa2xx_i2s_update(struct pxa2xx_i2s_s *i2s)
+{
+ int rfs, tfs;
+ rfs = SACR_RFTH(i2s->control[0]) < i2s->rx_len &&
+ !SACR_DREC(i2s->control[1]);
+ tfs = (i2s->tx_len || i2s->fifo_len < SACR_TFTH(i2s->control[0])) &&
+ i2s->enable && !SACR_DPRL(i2s->control[1]);
+
+ pxa2xx_dma_request(i2s->dma, PXA2XX_RX_RQ_I2S, rfs);
+ pxa2xx_dma_request(i2s->dma, PXA2XX_TX_RQ_I2S, tfs);
+
+ i2s->status &= 0xe0;
+ if (i2s->rx_len)
+ i2s->status |= 1 << 1; /* RNE */
+ if (i2s->enable)
+ i2s->status |= 1 << 2; /* BSY */
+ if (tfs)
+ i2s->status |= 1 << 3; /* TFS */
+ if (rfs)
+ i2s->status |= 1 << 4; /* RFS */
+ if (!(i2s->tx_len && i2s->enable))
+ i2s->status |= i2s->fifo_len << 8; /* TFL */
+ i2s->status |= MAX(i2s->rx_len, 0xf) << 12; /* RFL */
+
+ qemu_set_irq(i2s->irq, i2s->status & i2s->mask);
+}
+
+#define SACR0 0x00 /* Serial Audio Global Control register */
+#define SACR1 0x04 /* Serial Audio I2S/MSB-Justified Control register */
+#define SASR0 0x0c /* Serial Audio Interface and FIFO Status register */
+#define SAIMR 0x14 /* Serial Audio Interrupt Mask register */
+#define SAICR 0x18 /* Serial Audio Interrupt Clear register */
+#define SADIV 0x60 /* Serial Audio Clock Divider register */
+#define SADR 0x80 /* Serial Audio Data register */
+
+static uint32_t pxa2xx_i2s_read(void *opaque, target_phys_addr_t addr)
+{
+ struct pxa2xx_i2s_s *s = (struct pxa2xx_i2s_s *) opaque;
+ addr -= s->base;
+
+ switch (addr) {
+ case SACR0:
+ return s->control[0];
+ case SACR1:
+ return s->control[1];
+ case SASR0:
+ return s->status;
+ case SAIMR:
+ return s->mask;
+ case SAICR:
+ return 0;
+ case SADIV:
+ return s->clk;
+ case SADR:
+ if (s->rx_len > 0) {
+ s->rx_len --;
+ pxa2xx_i2s_update(s);
+ return s->codec_in(s->opaque);
+ }
+ return 0;
+ default:
+ printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+ break;
+ }
+ return 0;
+}
+
+static void pxa2xx_i2s_write(void *opaque, target_phys_addr_t addr,
+ uint32_t value)
+{
+ struct pxa2xx_i2s_s *s = (struct pxa2xx_i2s_s *) opaque;
+ uint32_t *sample;
+ addr -= s->base;
+
+ switch (addr) {
+ case SACR0:
+ if (value & (1 << 3)) /* RST */
+ pxa2xx_i2s_reset(s);
+ s->control[0] = value & 0xff3d;
+ if (!s->enable && (value & 1) && s->tx_len) { /* ENB */
+ for (sample = s->fifo; s->fifo_len > 0; s->fifo_len --, sample ++)
+ s->codec_out(s->opaque, *sample);
+ s->status &= ~(1 << 7); /* I2SOFF */
+ }
+ if (value & (1 << 4)) /* EFWR */
+ printf("%s: Attempt to use special function\n", __FUNCTION__);
+ s->enable = ((value ^ 4) & 5) == 5; /* ENB && !RST*/
+ pxa2xx_i2s_update(s);
+ break;
+ case SACR1:
+ s->control[1] = value & 0x0039;
+ if (value & (1 << 5)) /* ENLBF */
+ printf("%s: Attempt to use loopback function\n", __FUNCTION__);
+ if (value & (1 << 4)) /* DPRL */
+ s->fifo_len = 0;
+ pxa2xx_i2s_update(s);
+ break;
+ case SAIMR:
+ s->mask = value & 0x0078;
+ pxa2xx_i2s_update(s);
+ break;
+ case SAICR:
+ s->status &= ~(value & (3 << 5));
+ pxa2xx_i2s_update(s);
+ break;
+ case SADIV:
+ s->clk = value & 0x007f;
+ break;
+ case SADR:
+ if (s->tx_len && s->enable) {
+ s->tx_len --;
+ pxa2xx_i2s_update(s);
+ s->codec_out(s->opaque, value);
+ } else if (s->fifo_len < 16) {
+ s->fifo[s->fifo_len ++] = value;
+ pxa2xx_i2s_update(s);
+ }
+ break;
+ default:
+ printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+ }
+}
+
+static CPUReadMemoryFunc *pxa2xx_i2s_readfn[] = {
+ pxa2xx_i2s_read,
+ pxa2xx_i2s_read,
+ pxa2xx_i2s_read,
+};
+
+static CPUWriteMemoryFunc *pxa2xx_i2s_writefn[] = {
+ pxa2xx_i2s_write,
+ pxa2xx_i2s_write,
+ pxa2xx_i2s_write,
+};
+
+static void pxa2xx_i2s_data_req(void *opaque, int tx, int rx)
+{
+ struct pxa2xx_i2s_s *s = (struct pxa2xx_i2s_s *) opaque;
+ uint32_t *sample;
+
+ /* Signal FIFO errors */
+ if (s->enable && s->tx_len)
+ s->status |= 1 << 5; /* TUR */
+ if (s->enable && s->rx_len)
+ s->status |= 1 << 6; /* ROR */
+
+ /* Should be tx - MIN(tx, s->fifo_len) but we don't really need to
+ * handle the cases where it makes a difference. */
+ s->tx_len = tx - s->fifo_len;
+ s->rx_len = rx;
+ /* Note that is s->codec_out wasn't set, we wouldn't get called. */
+ if (s->enable)
+ for (sample = s->fifo; s->fifo_len; s->fifo_len --, sample ++)
+ s->codec_out(s->opaque, *sample);
+ pxa2xx_i2s_update(s);
+}
+
+static struct pxa2xx_i2s_s *pxa2xx_i2s_init(target_phys_addr_t base,
+ qemu_irq irq, struct pxa2xx_dma_state_s *dma)
+{
+ int iomemtype;
+ struct pxa2xx_i2s_s *s = (struct pxa2xx_i2s_s *)
+ qemu_mallocz(sizeof(struct pxa2xx_i2s_s));
+
+ s->base = base;
+ s->irq = irq;
+ s->dma = dma;
+ s->data_req = pxa2xx_i2s_data_req;
+
+ pxa2xx_i2s_reset(s);
+
+ iomemtype = cpu_register_io_memory(0, pxa2xx_i2s_readfn,
+ pxa2xx_i2s_writefn, s);
+ cpu_register_physical_memory(s->base & 0xfff00000, 0xfffff, iomemtype);
+
+ return s;
+}
+
+/* PXA Fast Infra-red Communications Port */
+struct pxa2xx_fir_s {
+ target_phys_addr_t base;
+ qemu_irq irq;
+ struct pxa2xx_dma_state_s *dma;
+ int enable;
+ CharDriverState *chr;
+
+ uint8_t control[3];
+ uint8_t status[2];
+
+ int rx_len;
+ int rx_start;
+ uint8_t rx_fifo[64];
+};
+
+static void pxa2xx_fir_reset(struct pxa2xx_fir_s *s)
+{
+ s->control[0] = 0x00;
+ s->control[1] = 0x00;
+ s->control[2] = 0x00;
+ s->status[0] = 0x00;
+ s->status[1] = 0x00;
+ s->enable = 0;
+}
+
+static inline void pxa2xx_fir_update(struct pxa2xx_fir_s *s)
+{
+ static const int tresh[4] = { 8, 16, 32, 0 };
+ int intr = 0;
+ if ((s->control[0] & (1 << 4)) && /* RXE */
+ s->rx_len >= tresh[s->control[2] & 3]) /* TRIG */
+ s->status[0] |= 1 << 4; /* RFS */
+ else
+ s->status[0] &= ~(1 << 4); /* RFS */
+ if (s->control[0] & (1 << 3)) /* TXE */
+ s->status[0] |= 1 << 3; /* TFS */
+ else
+ s->status[0] &= ~(1 << 3); /* TFS */
+ if (s->rx_len)
+ s->status[1] |= 1 << 2; /* RNE */
+ else
+ s->status[1] &= ~(1 << 2); /* RNE */
+ if (s->control[0] & (1 << 4)) /* RXE */
+ s->status[1] |= 1 << 0; /* RSY */
+ else
+ s->status[1] &= ~(1 << 0); /* RSY */
+
+ intr |= (s->control[0] & (1 << 5)) && /* RIE */
+ (s->status[0] & (1 << 4)); /* RFS */
+ intr |= (s->control[0] & (1 << 6)) && /* TIE */
+ (s->status[0] & (1 << 3)); /* TFS */
+ intr |= (s->control[2] & (1 << 4)) && /* TRAIL */
+ (s->status[0] & (1 << 6)); /* EOC */
+ intr |= (s->control[0] & (1 << 2)) && /* TUS */
+ (s->status[0] & (1 << 1)); /* TUR */
+ intr |= s->status[0] & 0x25; /* FRE, RAB, EIF */
+
+ pxa2xx_dma_request(s->dma, PXA2XX_RX_RQ_ICP, (s->status[0] >> 4) & 1);
+ pxa2xx_dma_request(s->dma, PXA2XX_TX_RQ_ICP, (s->status[0] >> 3) & 1);
+
+ qemu_set_irq(s->irq, intr && s->enable);
+}
+
+#define ICCR0 0x00 /* FICP Control register 0 */
+#define ICCR1 0x04 /* FICP Control register 1 */
+#define ICCR2 0x08 /* FICP Control register 2 */
+#define ICDR 0x0c /* FICP Data register */
+#define ICSR0 0x14 /* FICP Status register 0 */
+#define ICSR1 0x18 /* FICP Status register 1 */
+#define ICFOR 0x1c /* FICP FIFO Occupancy Status register */
+
+static uint32_t pxa2xx_fir_read(void *opaque, target_phys_addr_t addr)
+{
+ struct pxa2xx_fir_s *s = (struct pxa2xx_fir_s *) opaque;
+ uint8_t ret;
+ addr -= s->base;
+
+ switch (addr) {
+ case ICCR0:
+ return s->control[0];
+ case ICCR1:
+ return s->control[1];
+ case ICCR2:
+ return s->control[2];
+ case ICDR:
+ s->status[0] &= ~0x01;
+ s->status[1] &= ~0x72;
+ if (s->rx_len) {
+ s->rx_len --;
+ ret = s->rx_fifo[s->rx_start ++];
+ s->rx_start &= 63;
+ pxa2xx_fir_update(s);
+ return ret;
+ }
+ printf("%s: Rx FIFO underrun.\n", __FUNCTION__);
+ break;
+ case ICSR0:
+ return s->status[0];
+ case ICSR1:
+ return s->status[1] | (1 << 3); /* TNF */
+ case ICFOR:
+ return s->rx_len;
+ default:
+ printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+ break;
+ }
+ return 0;
+}
+
+static void pxa2xx_fir_write(void *opaque, target_phys_addr_t addr,
+ uint32_t value)
+{
+ struct pxa2xx_fir_s *s = (struct pxa2xx_fir_s *) opaque;
+ uint8_t ch;
+ addr -= s->base;
+
+ switch (addr) {
+ case ICCR0:
+ s->control[0] = value;
+ if (!(value & (1 << 4))) /* RXE */
+ s->rx_len = s->rx_start = 0;
+ if (!(value & (1 << 3))) /* TXE */
+ /* Nop */;
+ s->enable = value & 1; /* ITR */
+ if (!s->enable)
+ s->status[0] = 0;
+ pxa2xx_fir_update(s);
+ break;
+ case ICCR1:
+ s->control[1] = value;
+ break;
+ case ICCR2:
+ s->control[2] = value & 0x3f;
+ pxa2xx_fir_update(s);
+ break;
+ case ICDR:
+ if (s->control[2] & (1 << 2)) /* TXP */
+ ch = value;
+ else
+ ch = ~value;
+ if (s->chr && s->enable && (s->control[0] & (1 << 3))) /* TXE */
+ qemu_chr_write(s->chr, &ch, 1);
+ break;
+ case ICSR0:
+ s->status[0] &= ~(value & 0x66);
+ pxa2xx_fir_update(s);
+ break;
+ case ICFOR:
+ break;
+ default:
+ printf("%s: Bad register " REG_FMT "\n", __FUNCTION__, addr);
+ }
+}
+
+static CPUReadMemoryFunc *pxa2xx_fir_readfn[] = {
+ pxa2xx_fir_read,
+ pxa2xx_fir_read,
+ pxa2xx_fir_read,
+};
+
+static CPUWriteMemoryFunc *pxa2xx_fir_writefn[] = {
+ pxa2xx_fir_write,
+ pxa2xx_fir_write,
+ pxa2xx_fir_write,
+};
+
+static int pxa2xx_fir_is_empty(void *opaque)
+{
+ struct pxa2xx_fir_s *s = (struct pxa2xx_fir_s *) opaque;
+ return (s->rx_len < 64);
+}
+
+static void pxa2xx_fir_rx(void *opaque, const uint8_t *buf, int size)
+{
+ struct pxa2xx_fir_s *s = (struct pxa2xx_fir_s *) opaque;
+ if (!(s->control[0] & (1 << 4))) /* RXE */
+ return;
+
+ while (size --) {
+ s->status[1] |= 1 << 4; /* EOF */
+ if (s->rx_len >= 64) {
+ s->status[1] |= 1 << 6; /* ROR */
+ break;
+ }
+
+ if (s->control[2] & (1 << 3)) /* RXP */
+ s->rx_fifo[(s->rx_start + s->rx_len ++) & 63] = *(buf ++);
+ else
+ s->rx_fifo[(s->rx_start + s->rx_len ++) & 63] = ~*(buf ++);
+ }
+
+ pxa2xx_fir_update(s);
+}
+
+static void pxa2xx_fir_event(void *opaque, int event)
+{
+}
+
+static struct pxa2xx_fir_s *pxa2xx_fir_init(target_phys_addr_t base,
+ qemu_irq irq, struct pxa2xx_dma_state_s *dma,
+ CharDriverState *chr)
+{
+ int iomemtype;
+ struct pxa2xx_fir_s *s = (struct pxa2xx_fir_s *)
+ qemu_mallocz(sizeof(struct pxa2xx_fir_s));
+
+ s->base = base;
+ s->irq = irq;
+ s->dma = dma;
+ s->chr = chr;
+
+ pxa2xx_fir_reset(s);
+
+ iomemtype = cpu_register_io_memory(0, pxa2xx_fir_readfn,
+ pxa2xx_fir_writefn, s);
+ cpu_register_physical_memory(s->base, 0xfff, iomemtype);
+
+ if (chr)
+ qemu_chr_add_handlers(chr, pxa2xx_fir_is_empty,
+ pxa2xx_fir_rx, pxa2xx_fir_event, s);
+
+ return s;
+}
+
+void pxa2xx_reset(int line, int level, void *opaque)
+{
+ struct pxa2xx_state_s *s = (struct pxa2xx_state_s *) opaque;
+ if (level && (s->pm_regs[PCFR >> 2] & 0x10)) { /* GPR_EN */
+ cpu_reset(s->env);
+ /* TODO: reset peripherals */
+ }
+}
+
+/* Initialise a PXA270 integrated chip (ARM based core). */
+struct pxa2xx_state_s *pxa270_init(unsigned int sdram_size,
+ DisplayState *ds, const char *revision)
+{
+ struct pxa2xx_state_s *s;
+ struct pxa2xx_ssp_s *ssp;
+ int iomemtype, i;
+ s = (struct pxa2xx_state_s *) qemu_mallocz(sizeof(struct pxa2xx_state_s));
+
+ if (revision && strncmp(revision, "pxa27", 5)) {
+ fprintf(stderr, "Machine requires a PXA27x processor.\n");
+ exit(1);
+ }
+
+ s->env = cpu_init();
+ cpu_arm_set_model(s->env, revision ?: "pxa270");
+
+ /* SDRAM & Internal Memory Storage */
+ cpu_register_physical_memory(PXA2XX_SDRAM_BASE,
+ sdram_size, qemu_ram_alloc(sdram_size) | IO_MEM_RAM);
+ cpu_register_physical_memory(PXA2XX_INTERNAL_BASE,
+ 0x40000, qemu_ram_alloc(0x40000) | IO_MEM_RAM);
+
+ s->pic = pxa2xx_pic_init(0x40d00000, s->env);
+
+ s->dma = pxa27x_dma_init(0x40000000, s->pic[PXA2XX_PIC_DMA]);
+
+ pxa27x_timer_init(0x40a00000, &s->pic[PXA2XX_PIC_OST_0],
+ s->pic[PXA27X_PIC_OST_4_11], s->env);
+
+ s->gpio = pxa2xx_gpio_init(0x40e00000, s->env, s->pic, 121);
+
+ s->mmc = pxa2xx_mmci_init(0x41100000, s->pic[PXA2XX_PIC_MMC], s->dma);
+
+ for (i = 0; pxa270_serial[i].io_base; i ++)
+ if (serial_hds[i])
+ serial_mm_init(pxa270_serial[i].io_base, 2,
+ s->pic[pxa270_serial[i].irqn], serial_hds[i], 1);
+ else
+ break;
+ if (serial_hds[i])
+ s->fir = pxa2xx_fir_init(0x40800000, s->pic[PXA2XX_PIC_ICP],
+ s->dma, serial_hds[i]);
+
+ if (ds)
+ s->lcd = pxa2xx_lcdc_init(0x44000000, s->pic[PXA2XX_PIC_LCD], ds);
+
+ s->cm_base = 0x41300000;
+ s->cm_regs[CCCR >> 4] = 0x02000210; /* 416.0 MHz */
+ s->clkcfg = 0x00000009; /* Turbo mode active */
+ iomemtype = cpu_register_io_memory(0, pxa2xx_cm_readfn,
+ pxa2xx_cm_writefn, s);
+ cpu_register_physical_memory(s->cm_base, 0xfff, iomemtype);
+
+ cpu_arm_set_cp_io(s->env, 14, pxa2xx_cp14_read, pxa2xx_cp14_write, s);
+
+ s->mm_base = 0x48000000;
+ s->mm_regs[MDMRS >> 2] = 0x00020002;
+ s->mm_regs[MDREFR >> 2] = 0x03ca4000;
+ s->mm_regs[MECR >> 2] = 0x00000001; /* Two PC Card sockets */
+ iomemtype = cpu_register_io_memory(0, pxa2xx_mm_readfn,
+ pxa2xx_mm_writefn, s);
+ cpu_register_physical_memory(s->mm_base, 0xfff, iomemtype);
+
+ for (i = 0; pxa27x_ssp[i].io_base; i ++);
+ s->ssp = (struct pxa2xx_ssp_s **)
+ qemu_mallocz(sizeof(struct pxa2xx_ssp_s *) * i);
+ ssp = (struct pxa2xx_ssp_s *)
+ qemu_mallocz(sizeof(struct pxa2xx_ssp_s) * i);
+ for (i = 0; pxa27x_ssp[i].io_base; i ++) {
+ s->ssp[i] = &ssp[i];
+ ssp[i].base = pxa27x_ssp[i].io_base;
+ ssp[i].irq = s->pic[pxa27x_ssp[i].irqn];
+
+ iomemtype = cpu_register_io_memory(0, pxa2xx_ssp_readfn,
+ pxa2xx_ssp_writefn, &ssp[i]);
+ cpu_register_physical_memory(ssp[i].base, 0xfff, iomemtype);
+ }
+
+ if (usb_enabled) {
+ usb_ohci_init_memio(0x4c000000, 3, -1, s->pic[PXA2XX_PIC_USBH1]);
+ }
+
+ s->pcmcia[0] = pxa2xx_pcmcia_init(0x20000000);
+ s->pcmcia[1] = pxa2xx_pcmcia_init(0x30000000);
+
+ s->rtc_base = 0x40900000;
+ iomemtype = cpu_register_io_memory(0, pxa2xx_rtc_readfn,
+ pxa2xx_rtc_writefn, s);
+ cpu_register_physical_memory(s->rtc_base, 0xfff, iomemtype);
+ pxa2xx_rtc_reset(s);
+
+ /* Note that PM registers are in the same page with PWRI2C registers.
+ * As a workaround we don't map PWRI2C into memory and we expect
+ * PM handlers to call PWRI2C handlers when appropriate. */
+ s->i2c[0] = pxa2xx_i2c_init(0x40301600, s->pic[PXA2XX_PIC_I2C], 1);
+ s->i2c[1] = pxa2xx_i2c_init(0x40f00100, s->pic[PXA2XX_PIC_PWRI2C], 0);
+
+ s->pm_base = 0x40f00000;
+ iomemtype = cpu_register_io_memory(0, pxa2xx_pm_readfn,
+ pxa2xx_pm_writefn, s);
+ cpu_register_physical_memory(s->pm_base, 0xfff, iomemtype);
+
+ s->i2s = pxa2xx_i2s_init(0x40400000, s->pic[PXA2XX_PIC_I2S], s->dma);
+
+ /* GPIO1 resets the processor */
+ /* The handler can be overriden by board-specific code */
+ pxa2xx_gpio_handler_set(s->gpio, 1, pxa2xx_reset, s);
+ return s;
+}
+
+/* Initialise a PXA255 integrated chip (ARM based core). */
+struct pxa2xx_state_s *pxa255_init(unsigned int sdram_size,
+ DisplayState *ds)
+{
+ struct pxa2xx_state_s *s;
+ struct pxa2xx_ssp_s *ssp;
+ int iomemtype, i;
+ s = (struct pxa2xx_state_s *) qemu_mallocz(sizeof(struct pxa2xx_state_s));
+
+ s->env = cpu_init();
+ cpu_arm_set_model(s->env, "pxa255");
+
+ /* SDRAM & Internal Memory Storage */
+ cpu_register_physical_memory(PXA2XX_SDRAM_BASE,
+ sdram_size, qemu_ram_alloc(sdram_size) | IO_MEM_RAM);
+ cpu_register_physical_memory(PXA2XX_INTERNAL_BASE,
+ 0x40000, qemu_ram_alloc(0x40000) | IO_MEM_RAM);
+
+ s->pic = pxa2xx_pic_init(0x40d00000, s->env);
+
+ s->dma = pxa255_dma_init(0x40000000, s->pic[PXA2XX_PIC_DMA]);
+
+ pxa25x_timer_init(0x40a00000, &s->pic[PXA2XX_PIC_OST_0], s->env);
+
+ s->gpio = pxa2xx_gpio_init(0x40e00000, s->env, s->pic, 85);
+
+ s->mmc = pxa2xx_mmci_init(0x41100000, s->pic[PXA2XX_PIC_MMC], s->dma);
+
+ for (i = 0; pxa255_serial[i].io_base; i ++)
+ if (serial_hds[i])
+ serial_mm_init(pxa255_serial[i].io_base, 2,
+ s->pic[pxa255_serial[i].irqn], serial_hds[i], 1);
+ else
+ break;
+ if (serial_hds[i])
+ s->fir = pxa2xx_fir_init(0x40800000, s->pic[PXA2XX_PIC_ICP],
+ s->dma, serial_hds[i]);
+
+ if (ds)
+ s->lcd = pxa2xx_lcdc_init(0x44000000, s->pic[PXA2XX_PIC_LCD], ds);
+
+ s->cm_base = 0x41300000;
+ s->cm_regs[CCCR >> 4] = 0x02000210; /* 416.0 MHz */
+ s->clkcfg = 0x00000009; /* Turbo mode active */
+ iomemtype = cpu_register_io_memory(0, pxa2xx_cm_readfn,
+ pxa2xx_cm_writefn, s);
+ cpu_register_physical_memory(s->cm_base, 0xfff, iomemtype);
+
+ cpu_arm_set_cp_io(s->env, 14, pxa2xx_cp14_read, pxa2xx_cp14_write, s);
+
+ s->mm_base = 0x48000000;
+ s->mm_regs[MDMRS >> 2] = 0x00020002;
+ s->mm_regs[MDREFR >> 2] = 0x03ca4000;
+ s->mm_regs[MECR >> 2] = 0x00000001; /* Two PC Card sockets */
+ iomemtype = cpu_register_io_memory(0, pxa2xx_mm_readfn,
+ pxa2xx_mm_writefn, s);
+ cpu_register_physical_memory(s->mm_base, 0xfff, iomemtype);
+
+ for (i = 0; pxa255_ssp[i].io_base; i ++);
+ s->ssp = (struct pxa2xx_ssp_s **)
+ qemu_mallocz(sizeof(struct pxa2xx_ssp_s *) * i);
+ ssp = (struct pxa2xx_ssp_s *)
+ qemu_mallocz(sizeof(struct pxa2xx_ssp_s) * i);
+ for (i = 0; pxa255_ssp[i].io_base; i ++) {
+ s->ssp[i] = &ssp[i];
+ ssp[i].base = pxa255_ssp[i].io_base;
+ ssp[i].irq = s->pic[pxa255_ssp[i].irqn];
+
+ iomemtype = cpu_register_io_memory(0, pxa2xx_ssp_readfn,
+ pxa2xx_ssp_writefn, &ssp[i]);
+ cpu_register_physical_memory(ssp[i].base, 0xfff, iomemtype);
+ }
+
+ if (usb_enabled) {
+ usb_ohci_init_memio(0x4c000000, 3, -1, s->pic[PXA2XX_PIC_USBH1]);
+ }
+
+ s->pcmcia[0] = pxa2xx_pcmcia_init(0x20000000);
+ s->pcmcia[1] = pxa2xx_pcmcia_init(0x30000000);
+
+ s->rtc_base = 0x40900000;
+ iomemtype = cpu_register_io_memory(0, pxa2xx_rtc_readfn,
+ pxa2xx_rtc_writefn, s);
+ cpu_register_physical_memory(s->rtc_base, 0xfff, iomemtype);
+ pxa2xx_rtc_reset(s);
+
+ s->i2c[0] = pxa2xx_i2c_init(0x40301600, s->pic[PXA2XX_PIC_I2C], 1);
+ s->i2c[1] = pxa2xx_i2c_init(0x40f00100, s->pic[PXA2XX_PIC_PWRI2C], 0);
+
+ s->pm_base = 0x40f00000;
+ iomemtype = cpu_register_io_memory(0, pxa2xx_pm_readfn,
+ pxa2xx_pm_writefn, s);
+ cpu_register_physical_memory(s->pm_base, 0xfff, iomemtype);
+
+ s->i2s = pxa2xx_i2s_init(0x40400000, s->pic[PXA2XX_PIC_I2S], s->dma);
+
+ /* GPIO1 resets the processor */
+ /* The handler can be overriden by board-specific code */
+ pxa2xx_gpio_handler_set(s->gpio, 1, pxa2xx_reset, s);
+ return s;
+}
Modified: trunk/src/host/qemu-neo1973/hw/pxa2xx_dma.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/pxa2xx_dma.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/pxa2xx_dma.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -19,16 +19,13 @@
int request;
};
-/* The first element of an individual PIC state structures should
- * be a pointer to the handler routine. We allow the DMA to be used
- * as a PIC. */
+/* Allow the DMA to be used as a PIC. */
typedef void (*pxa2xx_dma_handler_t)(void *opaque, int irq, int level);
struct pxa2xx_dma_state_s {
pxa2xx_dma_handler_t handler;
target_phys_addr_t base;
- void *pic;
- int irq;
+ qemu_irq irq;
uint32_t stopintr;
uint32_t eorintr;
@@ -53,19 +50,19 @@
#define PXA2XX_DMA_NUM_REQUESTS 75
-#define DCSR0 0x0000 /* DMA Control / Status Register for Channel 0 */
-#define DCSR31 0x007c /* DMA Control / Status Register for Channel 31 */
-#define DALGN 0x00a0 /* DMA Alignment Register */
-#define DPCSR 0x00a4 /* DMA Programmed I/O Control Status Register */
-#define DRQSR0 0x00e0 /* DMA DREQ<0> Status Register */
-#define DRQSR1 0x00e4 /* DMA DREQ<1> Status Register */
-#define DRQSR2 0x00e8 /* DMA DREQ<2> Status Register */
-#define DINT 0x00f0 /* DMA Interrupt Register */
-#define DRCMR0 0x0100 /* Request to Channel Map Register 0 */
-#define DRCMR63 0x01fc /* Request to Channel Map Register 63 */
+#define DCSR0 0x0000 /* DMA Control / Status register for Channel 0 */
+#define DCSR31 0x007c /* DMA Control / Status register for Channel 31 */
+#define DALGN 0x00a0 /* DMA Alignment register */
+#define DPCSR 0x00a4 /* DMA Programmed I/O Control Status register */
+#define DRQSR0 0x00e0 /* DMA DREQ<0> Status register */
+#define DRQSR1 0x00e4 /* DMA DREQ<1> Status register */
+#define DRQSR2 0x00e8 /* DMA DREQ<2> Status register */
+#define DINT 0x00f0 /* DMA Interrupt register */
+#define DRCMR0 0x0100 /* Request to Channel Map register 0 */
+#define DRCMR63 0x01fc /* Request to Channel Map register 63 */
#define D_CH0 0x0200 /* Channel 0 Descriptor start */
-#define DRCMR64 0x1100 /* Request to Channel Map Register 64 */
-#define DRCMR74 0x1128 /* Request to Channel Map Register 74 */
+#define DRCMR64 0x1100 /* Request to Channel Map register 64 */
+#define DRCMR74 0x1128 /* Request to Channel Map register 74 */
/* Per-channel register */
#define DDADR 0x00
@@ -142,9 +139,9 @@
}
if (s->stopintr | s->eorintr | s->rasintr | s->startintr | s->endintr)
- pic_set_irq_new(s->pic, s->irq, 1);
+ qemu_irq_raise(s->irq);
else
- pic_set_irq_new(s->pic, s->irq, 0);
+ qemu_irq_lower(s->irq);
}
static inline void pxa2xx_dma_descriptor_fetch(
@@ -305,7 +302,8 @@
}
}
- cpu_abort(cpu_single_env, "%s: Bad offset 0x%04x\n", __FUNCTION__, offset);
+ cpu_abort(cpu_single_env,
+ "%s: Bad offset 0x%04lx\n", __FUNCTION__, offset);
return 7;
}
@@ -403,7 +401,7 @@
break;
}
fail:
- cpu_abort(cpu_single_env, "%s: Bad offset 0x%04x\n",
+ cpu_abort(cpu_single_env, "%s: Bad offset 0x%04lx\n",
__FUNCTION__, offset);
}
}
@@ -433,7 +431,7 @@
};
static struct pxa2xx_dma_state_s *pxa2xx_dma_init(target_phys_addr_t base,
- void *pic, int irq, int channels)
+ qemu_irq irq, int channels)
{
int i, iomemtype;
struct pxa2xx_dma_state_s *s;
@@ -443,7 +441,6 @@
s->channels = channels;
s->chan = qemu_mallocz(sizeof(struct pxa2xx_dma_channel_s) * s->channels);
s->base = base;
- s->pic = pic;
s->irq = irq;
s->handler = (pxa2xx_dma_handler_t) pxa2xx_dma_request;
s->req = qemu_mallocz(sizeof(int) * PXA2XX_DMA_NUM_REQUESTS);
@@ -462,15 +459,15 @@
}
struct pxa2xx_dma_state_s *pxa27x_dma_init(target_phys_addr_t base,
- void *pic, int irq)
+ qemu_irq irq)
{
- return pxa2xx_dma_init(base, pic, irq, PXA27X_DMA_NUM_CHANNELS);
+ return pxa2xx_dma_init(base, irq, PXA27X_DMA_NUM_CHANNELS);
}
struct pxa2xx_dma_state_s *pxa255_dma_init(target_phys_addr_t base,
- void *pic, int irq)
+ qemu_irq irq)
{
- return pxa2xx_dma_init(base, pic, irq, PXA255_DMA_NUM_CHANNELS);
+ return pxa2xx_dma_init(base, irq, PXA255_DMA_NUM_CHANNELS);
}
void pxa2xx_dma_request(struct pxa2xx_dma_state_s *s, int req_num, int on)
Modified: trunk/src/host/qemu-neo1973/hw/pxa2xx_gpio.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/pxa2xx_gpio.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/pxa2xx_gpio.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -13,7 +13,7 @@
struct pxa2xx_gpio_info_s {
target_phys_addr_t base;
- void *pic;
+ qemu_irq *pic;
int lines;
CPUState *cpu_env;
@@ -69,19 +69,19 @@
static void pxa2xx_gpio_irq_update(struct pxa2xx_gpio_info_s *s)
{
if (s->status[0] & (1 << 0))
- pic_set_irq_new(s->pic, PXA2XX_PIC_GPIO_0, 1);
+ qemu_irq_raise(s->pic[PXA2XX_PIC_GPIO_0]);
else
- pic_set_irq_new(s->pic, PXA2XX_PIC_GPIO_0, 0);
+ qemu_irq_lower(s->pic[PXA2XX_PIC_GPIO_0]);
if (s->status[0] & (1 << 1))
- pic_set_irq_new(s->pic, PXA2XX_PIC_GPIO_1, 1);
+ qemu_irq_raise(s->pic[PXA2XX_PIC_GPIO_1]);
else
- pic_set_irq_new(s->pic, PXA2XX_PIC_GPIO_1, 0);
+ qemu_irq_lower(s->pic[PXA2XX_PIC_GPIO_1]);
if ((s->status[0] & ~3) | s->status[1] | s->status[2] | s->status[3])
- pic_set_irq_new(s->pic, PXA2XX_PIC_GPIO_X, 1);
+ qemu_irq_raise(s->pic[PXA2XX_PIC_GPIO_X]);
else
- pic_set_irq_new(s->pic, PXA2XX_PIC_GPIO_X, 0);
+ qemu_irq_lower(s->pic[PXA2XX_PIC_GPIO_X]);
}
/* Bitmap of pins used as standby and sleep wake-up sources. */
@@ -149,34 +149,34 @@
bank = pxa2xx_gpio_regs[offset].bank;
switch (pxa2xx_gpio_regs[offset].reg) {
- case GPDR: /* GPIO Pin-Direction Registers */
+ case GPDR: /* GPIO Pin-Direction registers */
return s->dir[bank];
- case GRER: /* GPIO Rising-Edge Detect Enable Registers */
+ case GRER: /* GPIO Rising-Edge Detect Enable registers */
return s->rising[bank];
- case GFER: /* GPIO Falling-Edge Detect Enable Registers */
+ case GFER: /* GPIO Falling-Edge Detect Enable registers */
return s->falling[bank];
- case GAFR_L: /* GPIO Alternate Function Registers */
+ case GAFR_L: /* GPIO Alternate Function registers */
return s->gafr[bank * 2];
- case GAFR_U: /* GPIO Alternate Function Registers */
+ case GAFR_U: /* GPIO Alternate Function registers */
return s->gafr[bank * 2 + 1];
- case GPLR: /* GPIO Pin-Level Registers */
+ case GPLR: /* GPIO Pin-Level registers */
ret = (s->olevel[bank] & s->dir[bank]) |
(s->ilevel[bank] & ~s->dir[bank]);
if (s->read_notify)
s->read_notify(s->opaque);
return ret;
- case GEDR: /* GPIO Edge Detect Status Registers */
+ case GEDR: /* GPIO Edge Detect Status registers */
return s->status[bank];
default:
cpu_abort(cpu_single_env,
- "%s: Bad offset %x\n", __FUNCTION__, offset);
+ "%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset);
}
return 0;
@@ -193,45 +193,45 @@
bank = pxa2xx_gpio_regs[offset].bank;
switch (pxa2xx_gpio_regs[offset].reg) {
- case GPDR: /* GPIO Pin-Direction Registers */
+ case GPDR: /* GPIO Pin-Direction registers */
s->dir[bank] = value;
pxa2xx_gpio_handler_update(s);
break;
- case GPSR: /* GPIO Pin-Output Set Registers */
+ case GPSR: /* GPIO Pin-Output Set registers */
s->olevel[bank] |= value;
pxa2xx_gpio_handler_update(s);
break;
- case GPCR: /* GPIO Pin-Output Clear Registers */
+ case GPCR: /* GPIO Pin-Output Clear registers */
s->olevel[bank] &= ~value;
pxa2xx_gpio_handler_update(s);
break;
- case GRER: /* GPIO Rising-Edge Detect Enable Registers */
+ case GRER: /* GPIO Rising-Edge Detect Enable registers */
s->rising[bank] = value;
break;
- case GFER: /* GPIO Falling-Edge Detect Enable Registers */
+ case GFER: /* GPIO Falling-Edge Detect Enable registers */
s->falling[bank] = value;
break;
- case GAFR_L: /* GPIO Alternate Function Registers */
+ case GAFR_L: /* GPIO Alternate Function registers */
s->gafr[bank * 2] = value;
break;
- case GAFR_U: /* GPIO Alternate Function Registers */
+ case GAFR_U: /* GPIO Alternate Function registers */
s->gafr[bank * 2 + 1] = value;
break;
- case GEDR: /* GPIO Edge Detect Status Registers */
+ case GEDR: /* GPIO Edge Detect Status registers */
s->status[bank] &= ~value;
pxa2xx_gpio_irq_update(s);
break;
default:
cpu_abort(cpu_single_env,
- "%s: Bad offset %x\n", __FUNCTION__, offset);
+ "%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset);
}
}
@@ -248,7 +248,7 @@
};
struct pxa2xx_gpio_info_s *pxa2xx_gpio_init(target_phys_addr_t base,
- CPUState *env, void *pic, int lines)
+ CPUState *env, qemu_irq *pic, int lines)
{
int iomemtype;
struct pxa2xx_gpio_info_s *s;
Modified: trunk/src/host/qemu-neo1973/hw/pxa2xx_lcd.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/pxa2xx_lcd.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/pxa2xx_lcd.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -13,7 +13,7 @@
struct pxa2xx_lcdc_s {
target_phys_addr_t base;
- void *pic;
+ qemu_irq irq;
int irqlevel;
int invalidated;
@@ -73,44 +73,44 @@
uint32_t ldcmd;
};
-#define LCCR0 0x000 /* LCD Controller Control Register 0 */
-#define LCCR1 0x004 /* LCD Controller Control Register 1 */
-#define LCCR2 0x008 /* LCD Controller Control Register 2 */
-#define LCCR3 0x00c /* LCD Controller Control Register 3 */
-#define LCCR4 0x010 /* LCD Controller Control Register 4 */
-#define LCCR5 0x014 /* LCD Controller Control Register 5 */
+#define LCCR0 0x000 /* LCD Controller Control register 0 */
+#define LCCR1 0x004 /* LCD Controller Control register 1 */
+#define LCCR2 0x008 /* LCD Controller Control register 2 */
+#define LCCR3 0x00c /* LCD Controller Control register 3 */
+#define LCCR4 0x010 /* LCD Controller Control register 4 */
+#define LCCR5 0x014 /* LCD Controller Control register 5 */
-#define FBR0 0x020 /* DMA Channel 0 Frame Branch Register */
-#define FBR1 0x024 /* DMA Channel 1 Frame Branch Register */
-#define FBR2 0x028 /* DMA Channel 2 Frame Branch Register */
-#define FBR3 0x02c /* DMA Channel 3 Frame Branch Register */
-#define FBR4 0x030 /* DMA Channel 4 Frame Branch Register */
-#define FBR5 0x110 /* DMA Channel 5 Frame Branch Register */
-#define FBR6 0x114 /* DMA Channel 6 Frame Branch Register */
+#define FBR0 0x020 /* DMA Channel 0 Frame Branch register */
+#define FBR1 0x024 /* DMA Channel 1 Frame Branch register */
+#define FBR2 0x028 /* DMA Channel 2 Frame Branch register */
+#define FBR3 0x02c /* DMA Channel 3 Frame Branch register */
+#define FBR4 0x030 /* DMA Channel 4 Frame Branch register */
+#define FBR5 0x110 /* DMA Channel 5 Frame Branch register */
+#define FBR6 0x114 /* DMA Channel 6 Frame Branch register */
-#define LCSR1 0x034 /* LCD Controller Status Register 1 */
-#define LCSR0 0x038 /* LCD Controller Status Register 0 */
-#define LIIDR 0x03c /* LCD Controller Interrupt ID Register */
+#define LCSR1 0x034 /* LCD Controller Status register 1 */
+#define LCSR0 0x038 /* LCD Controller Status register 0 */
+#define LIIDR 0x03c /* LCD Controller Interrupt ID register */
-#define TRGBR 0x040 /* TMED RGB Seed Register */
-#define TCR 0x044 /* TMED Control Register */
+#define TRGBR 0x040 /* TMED RGB Seed register */
+#define TCR 0x044 /* TMED Control register */
-#define OVL1C1 0x050 /* Overlay 1 Control Register 1 */
-#define OVL1C2 0x060 /* Overlay 1 Control Register 2 */
-#define OVL2C1 0x070 /* Overlay 2 Control Register 1 */
-#define OVL2C2 0x080 /* Overlay 2 Control Register 2 */
-#define CCR 0x090 /* Cursor Control Register */
+#define OVL1C1 0x050 /* Overlay 1 Control register 1 */
+#define OVL1C2 0x060 /* Overlay 1 Control register 2 */
+#define OVL2C1 0x070 /* Overlay 2 Control register 1 */
+#define OVL2C2 0x080 /* Overlay 2 Control register 2 */
+#define CCR 0x090 /* Cursor Control register */
-#define CMDCR 0x100 /* Command Control Register */
-#define PRSR 0x104 /* Panel Read Status Register */
+#define CMDCR 0x100 /* Command Control register */
+#define PRSR 0x104 /* Panel Read Status register */
#define PXA_LCDDMA_CHANS 7
-#define DMA_FDADR 0x00 /* Frame Descriptor Address Register */
-#define DMA_FSADR 0x04 /* Frame Source Address Register */
-#define DMA_FIDR 0x08 /* Frame ID Register */
-#define DMA_LDCMD 0x0c /* Command Register */
+#define DMA_FDADR 0x00 /* Frame Descriptor Address register */
+#define DMA_FSADR 0x04 /* Frame Source Address register */
+#define DMA_FIDR 0x08 /* Frame ID register */
+#define DMA_LDCMD 0x0c /* Command register */
-/* LCD Buffer Strength Control Register */
+/* LCD Buffer Strength Control register */
#define BSCNTR 0x04000054
/* Bitfield masks */
@@ -190,7 +190,7 @@
level |= (s->status[0] & LCSR0_CMDINT) && !(s->control[0] & LCCR0_CMDIM);
level |= (s->status[1] & ~s->control[5]);
- pic_set_irq_new(s->pic, PXA2XX_PIC_LCD, !!level);
+ qemu_set_irq(s->irq, !!level);
s->irqlevel = level;
}
@@ -300,11 +300,11 @@
} else
descptr = s->dma_ch[i].descriptor;
- if (!(descptr >= PXA2XX_RAM_BASE && descptr +
- sizeof(*desc[i]) <= PXA2XX_RAM_BASE + phys_ram_size))
+ if (!(descptr >= PXA2XX_SDRAM_BASE && descptr +
+ sizeof(*desc[i]) <= PXA2XX_SDRAM_BASE + phys_ram_size))
continue;
- descptr -= PXA2XX_RAM_BASE;
+ descptr -= PXA2XX_SDRAM_BASE;
desc[i] = (struct pxa_frame_descriptor_s *) (phys_ram_base + descptr);
s->dma_ch[i].descriptor = desc[i]->fdaddr;
s->dma_ch[i].source = desc[i]->fsaddr;
@@ -402,7 +402,7 @@
default:
fail:
cpu_abort(cpu_single_env,
- "%s: Bad offset %x\n", __FUNCTION__, offset);
+ "%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset);
}
return 0;
@@ -559,7 +559,7 @@
default:
fail:
cpu_abort(cpu_single_env,
- "%s: Bad offset %x\n", __FUNCTION__, offset);
+ "%s: Bad offset " REG_FMT "\n", __FUNCTION__, offset);
}
}
@@ -722,7 +722,7 @@
dest_width = s->xres * s->dest_width;
addr = (ram_addr_t) (fb - phys_ram_base);
- start = addr + (s->yres + 1) * src_width;
+ start = addr + s->yres * src_width;
end = addr;
dirty[0] = dirty[1] = cpu_physical_memory_get_dirty(start, VGA_DIRTY_FLAG);
for (y = 0; y < s->yres; y ++) {
@@ -750,7 +750,8 @@
dest += dest_width;
}
- cpu_physical_memory_reset_dirty(start, end, VGA_DIRTY_FLAG);
+ if (end > start)
+ cpu_physical_memory_reset_dirty(start, end, VGA_DIRTY_FLAG);
}
static void pxa2xx_lcdc_dma0_redraw_vert(struct pxa2xx_lcdc_s *s,
@@ -793,8 +794,7 @@
dest, src, s->xres, -dest_width);
if (addr < start)
start = addr;
- if (new_addr > end)
- end = new_addr;
+ end = new_addr;
if (y < *miny)
*miny = y;
if (y >= *maxy)
@@ -806,7 +806,8 @@
dest += s->dest_width;
}
- cpu_physical_memory_reset_dirty(start, end, VGA_DIRTY_FLAG);
+ if (end > start)
+ cpu_physical_memory_reset_dirty(start, end, VGA_DIRTY_FLAG);
}
static void pxa2xx_lcdc_resize(struct pxa2xx_lcdc_s *s)
@@ -853,12 +854,12 @@
continue;
}
fbptr = s->dma_ch[ch].source;
- if (!(fbptr >= PXA2XX_RAM_BASE &&
- fbptr <= PXA2XX_RAM_BASE + phys_ram_size)) {
+ if (!(fbptr >= PXA2XX_SDRAM_BASE &&
+ fbptr <= PXA2XX_SDRAM_BASE + phys_ram_size)) {
pxa2xx_dma_ber_set(s, ch);
continue;
}
- fbptr -= PXA2XX_RAM_BASE;
+ fbptr -= PXA2XX_SDRAM_BASE;
fb = phys_ram_base + fbptr;
if (s->dma_ch[ch].command & LDCMD_PAL) {
@@ -935,7 +936,7 @@
#define BITS 32
#include "pxa2xx_template.h"
-struct pxa2xx_lcdc_s *pxa2xx_lcdc_init(target_phys_addr_t base, void *pic,
+struct pxa2xx_lcdc_s *pxa2xx_lcdc_init(target_phys_addr_t base, qemu_irq irq,
DisplayState *ds)
{
int iomemtype;
@@ -944,7 +945,7 @@
s = (struct pxa2xx_lcdc_s *) qemu_mallocz(sizeof(struct pxa2xx_lcdc_s));
s->base = base;
s->invalidated = 1;
- s->pic = pic;
+ s->irq = irq;
s->ds = ds;
pxa2xx_lcdc_orientation(s, graphic_rotate);
Modified: trunk/src/host/qemu-neo1973/hw/pxa2xx_mmci.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/pxa2xx_mmci.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/pxa2xx_mmci.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -12,10 +12,10 @@
struct pxa2xx_mmci_s {
target_phys_addr_t base;
- void *pic;
+ qemu_irq irq;
void *dma;
- struct sd_state_s *card;
+ SDState *card;
uint32_t status;
uint32_t clkrt;
@@ -45,26 +45,26 @@
int ac_width;
};
-#define MMC_STRPCL 0x00 /* MMC Clock Start/Stop Register */
-#define MMC_STAT 0x04 /* MMC Status Register */
-#define MMC_CLKRT 0x08 /* MMC Clock Rate Register */
-#define MMC_SPI 0x0c /* MMC SPI Mode Register */
-#define MMC_CMDAT 0x10 /* MMC Command/Data Register */
-#define MMC_RESTO 0x14 /* MMC Response Time-Out Register */
-#define MMC_RDTO 0x18 /* MMC Read Time-Out Register */
-#define MMC_BLKLEN 0x1c /* MMC Block Length Register */
-#define MMC_NUMBLK 0x20 /* MMC Number of Blocks Register */
-#define MMC_PRTBUF 0x24 /* MMC Buffer Partly Full Register */
-#define MMC_I_MASK 0x28 /* MMC Interrupt Mask Register */
-#define MMC_I_REG 0x2c /* MMC Interrupt Request Register */
-#define MMC_CMD 0x30 /* MMC Command Register */
-#define MMC_ARGH 0x34 /* MMC Argument High Register */
-#define MMC_ARGL 0x38 /* MMC Argument Low Register */
+#define MMC_STRPCL 0x00 /* MMC Clock Start/Stop register */
+#define MMC_STAT 0x04 /* MMC Status register */
+#define MMC_CLKRT 0x08 /* MMC Clock Rate register */
+#define MMC_SPI 0x0c /* MMC SPI Mode register */
+#define MMC_CMDAT 0x10 /* MMC Command/Data register */
+#define MMC_RESTO 0x14 /* MMC Response Time-Out register */
+#define MMC_RDTO 0x18 /* MMC Read Time-Out register */
+#define MMC_BLKLEN 0x1c /* MMC Block Length register */
+#define MMC_NUMBLK 0x20 /* MMC Number of Blocks register */
+#define MMC_PRTBUF 0x24 /* MMC Buffer Partly Full register */
+#define MMC_I_MASK 0x28 /* MMC Interrupt Mask register */
+#define MMC_I_REG 0x2c /* MMC Interrupt Request register */
+#define MMC_CMD 0x30 /* MMC Command register */
+#define MMC_ARGH 0x34 /* MMC Argument High register */
+#define MMC_ARGL 0x38 /* MMC Argument Low register */
#define MMC_RES 0x3c /* MMC Response FIFO */
#define MMC_RXFIFO 0x40 /* MMC Receive FIFO */
#define MMC_TXFIFO 0x44 /* MMC Transmit FIFO */
-#define MMC_RDWAIT 0x48 /* MMC RD_WAIT Register */
-#define MMC_BLKS_REM 0x4c /* MMC Blocks Remaining Register */
+#define MMC_RDWAIT 0x48 /* MMC RD_WAIT register */
+#define MMC_BLKS_REM 0x4c /* MMC Blocks Remaining register */
/* Bitfield masks */
#define STRPCL_STOP_CLK (1 << 0)
@@ -102,13 +102,13 @@
if (s->cmdat & CMDAT_DMA_EN) {
mask |= INT_RXFIFO_REQ | INT_TXFIFO_REQ;
- pic_set_irq_new(s->dma, PXA2XX_RX_RQ_MMCI,
- !!(s->intreq & INT_RXFIFO_REQ));
- pic_set_irq_new(s->dma, PXA2XX_TX_RQ_MMCI,
- !!(s->intreq & INT_TXFIFO_REQ));
+ pxa2xx_dma_request((struct pxa2xx_dma_state_s *) s->dma,
+ PXA2XX_RX_RQ_MMCI, !!(s->intreq & INT_RXFIFO_REQ));
+ pxa2xx_dma_request((struct pxa2xx_dma_state_s *) s->dma,
+ PXA2XX_TX_RQ_MMCI, !!(s->intreq & INT_TXFIFO_REQ));
}
- pic_set_irq_new(s->pic, PXA2XX_PIC_MMC, !!(s->intreq & ~mask));
+ qemu_set_irq(s->irq, !!(s->intreq & ~mask));
}
static void pxa2xx_mmci_fifo_update(struct pxa2xx_mmci_s *s)
@@ -118,7 +118,7 @@
if (s->cmdat & CMDAT_WR_RD) {
while (s->bytesleft && s->tx_len) {
- sd_write_datline(s->card, s->tx_fifo[s->tx_start ++]);
+ sd_write_data(s->card, s->tx_fifo[s->tx_start ++]);
s->tx_start &= 0x1f;
s->tx_len --;
s->bytesleft --;
@@ -128,7 +128,7 @@
} else
while (s->bytesleft && s->rx_len < 32) {
s->rx_fifo[(s->rx_start + (s->rx_len ++)) & 0x1f] =
- sd_read_datline(s->card);
+ sd_read_data(s->card);
s->bytesleft --;
s->intreq |= INT_RXFIFO_REQ;
}
@@ -149,9 +149,9 @@
static void pxa2xx_mmci_wakequeues(struct pxa2xx_mmci_s *s)
{
- int rsplen;
+ int rsplen, i;
struct sd_request_s request;
- union sd_response_u response;
+ uint8_t response[16];
s->active = 1;
s->rx_len = 0;
@@ -162,53 +162,36 @@
request.arg = s->arg;
request.crc = 0; /* FIXME */
- response = sd_write_cmdline(s->card, request, &rsplen);
+ rsplen = sd_do_command(s->card, &request, response);
s->intreq |= INT_END_CMD;
memset(s->resp_fifo, 0, sizeof(s->resp_fifo));
switch (s->cmdat & CMDAT_RES_TYPE) {
-#define PXAMMCI_RESP(wd, value) \
- s->resp_fifo[(wd) + 0] |= (value) >> 8; \
- s->resp_fifo[(wd) + 1] |= (value) << 8;
+#define PXAMMCI_RESP(wd, value0, value1) \
+ s->resp_fifo[(wd) + 0] |= (value0); \
+ s->resp_fifo[(wd) + 1] |= (value1) << 8;
case 0: /* No response */
goto complete;
case 1: /* R1, R4, R5 or R6 */
- if (rsplen < 48)
+ if (rsplen < 4)
goto timeout;
-
- if (request.cmd == 3) { /* R6 */
- PXAMMCI_RESP(0, response.r6.arg);
- PXAMMCI_RESP(1, response.r6.status);
- } else {
- PXAMMCI_RESP(0, response.r1.status >> 16);
- PXAMMCI_RESP(1, response.r1.status & 0x0000ffff);
- }
goto complete;
case 2: /* R2 */
- if (rsplen < 128)
+ if (rsplen < 16)
goto timeout;
-
- PXAMMCI_RESP(0, bswap16(response.r2.reg[0]));
- PXAMMCI_RESP(1, bswap16(response.r2.reg[1]));
- PXAMMCI_RESP(2, bswap16(response.r2.reg[2]));
- PXAMMCI_RESP(3, bswap16(response.r2.reg[3]));
- PXAMMCI_RESP(4, bswap16(response.r2.reg[4]));
- PXAMMCI_RESP(5, bswap16(response.r2.reg[5]));
- PXAMMCI_RESP(6, bswap16(response.r2.reg[6]));
- PXAMMCI_RESP(7, bswap16(response.r2.reg[7]));
goto complete;
case 3: /* R3 */
- if (rsplen < 32)
+ if (rsplen < 4)
goto timeout;
-
- PXAMMCI_RESP(0, response.r3.ocr_reg >> 16);
- PXAMMCI_RESP(1, response.r3.ocr_reg & 0x0000ffff);
goto complete;
complete:
+ for (i = 0; rsplen > 0; i ++, rsplen -= 2) {
+ PXAMMCI_RESP(i, response[i * 2], response[i * 2 + 1]);
+ }
s->status |= STAT_END_CMDRES;
if (!(s->cmdat & CMDAT_DATA_EN))
@@ -284,7 +267,8 @@
case MMC_BLKS_REM:
return s->numblk;
default:
- cpu_abort(cpu_single_env, "%s: Bad offset %x\n", __FUNCTION__, offset);
+ cpu_abort(cpu_single_env, "%s: Bad offset " REG_FMT "\n",
+ __FUNCTION__, offset);
}
return 0;
@@ -397,7 +381,8 @@
break;
default:
- cpu_abort(cpu_single_env, "%s: Bad offset %x\n", __FUNCTION__, offset);
+ cpu_abort(cpu_single_env, "%s: Bad offset " REG_FMT "\n",
+ __FUNCTION__, offset);
}
}
@@ -459,14 +444,14 @@
};
struct pxa2xx_mmci_s *pxa2xx_mmci_init(target_phys_addr_t base,
- void *pic, void *dma)
+ qemu_irq irq, void *dma)
{
int iomemtype;
struct pxa2xx_mmci_s *s;
s = (struct pxa2xx_mmci_s *) qemu_mallocz(sizeof(struct pxa2xx_mmci_s));
s->base = base;
- s->pic = pic;
+ s->irq = irq;
s->dma = dma;
iomemtype = cpu_register_io_memory(0, pxa2xx_mmci_readfn,
@@ -474,7 +459,7 @@
cpu_register_physical_memory(base, 0x000fffff, iomemtype);
/* Instantiate the actual storage */
- s->card = sd_init();
+ s->card = sd_init(sd_bdrv);
return s;
}
Modified: trunk/src/host/qemu-neo1973/hw/pxa2xx_pcmcia.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/pxa2xx_pcmcia.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/pxa2xx_pcmcia.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -16,10 +16,8 @@
target_phys_addr_t attr_base;
target_phys_addr_t io_base;
- void *pic;
- int irq;
- int cd_irq;
- void (*set_irq)(void *opaque, int line, int level);
+ qemu_irq irq;
+ qemu_irq cd_irq;
};
static uint32_t pxa2xx_pcmcia_common_read(void *opaque,
@@ -133,10 +131,10 @@
static void pxa2xx_pcmcia_set_irq(void *opaque, int line, int level)
{
struct pxa2xx_pcmcia_s *s = (struct pxa2xx_pcmcia_s *) opaque;
- if (!s->set_irq)
+ if (!s->irq)
return;
- s->set_irq(s->pic, s->irq, level);
+ qemu_set_irq(s->irq, level);
}
struct pxa2xx_pcmcia_s *pxa2xx_pcmcia_init(target_phys_addr_t base)
@@ -171,8 +169,7 @@
s->slot.slot_string = "PXA PC Card Socket 1";
else
s->slot.slot_string = "PXA PC Card Socket 0";
- s->slot.opaque = s;
- s->slot.set_irq = pxa2xx_pcmcia_set_irq;
+ s->slot.irq = qemu_allocate_irqs(pxa2xx_pcmcia_set_irq, s, 1)[0];
pcmcia_socket_register(&s->slot);
return s;
}
@@ -184,8 +181,8 @@
if (s->slot.attached)
return -EEXIST;
- if (s->set_irq) {
- s->set_irq(s->pic, s->cd_irq, 1);
+ if (s->cd_irq) {
+ qemu_irq_raise(s->cd_irq);
}
s->card = card;
@@ -210,21 +207,18 @@
s->slot.attached = 0;
- if (s->set_irq) {
- s->set_irq(s->pic, s->irq, 0);
- s->set_irq(s->pic, s->cd_irq, 0);
- }
+ if (s->irq)
+ qemu_irq_lower(s->irq);
+ if (s->cd_irq)
+ qemu_irq_lower(s->cd_irq);
return 0;
}
/* Who to notify on card events */
-void pxa2xx_pcmcia_set_irq_cb(void *opaque, void (*set_irq)(void *opaque,
- int line, int level), int irq, int cd_irq, void *pic)
+void pxa2xx_pcmcia_set_irq_cb(void *opaque, qemu_irq irq, qemu_irq cd_irq)
{
struct pxa2xx_pcmcia_s *s = (struct pxa2xx_pcmcia_s *) opaque;
- s->set_irq = set_irq;
- s->pic = pic;
s->irq = irq;
s->cd_irq = cd_irq;
}
Modified: trunk/src/host/qemu-neo1973/hw/pxa2xx_pic.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/pxa2xx_pic.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/pxa2xx_pic.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -27,24 +27,16 @@
#define IPR32 0xb0 /* Interrupt Controller Priority register 32 */
#define IPR39 0xcc /* Interrupt Controller Priority register 39 */
-/* The first element of an individual PIC state structures should
- * be a pointer to the handler routine. */
-typedef void (*pxa2xx_pic_handler_t)(void *opaque, int irq, int level);
-
#define PXA2XX_PIC_SRCS 40
struct pxa2xx_pic_state_s {
- pxa2xx_pic_handler_t handler;
- CPUState *cpu_env;
target_phys_addr_t base;
+ CPUState *cpu_env;
uint32_t int_enabled[2];
uint32_t int_pending[2];
uint32_t is_fiq[2];
uint32_t int_idle;
uint32_t priority[PXA2XX_PIC_SRCS];
- void *parent;
- int parent_irq;
- int parent_fiq;
};
static void pxa2xx_pic_update(void *opaque)
@@ -156,7 +148,7 @@
case ICHP: /* Highest Priority register */
return pxa2xx_pic_highest(s);
default:
- printf("%s: Bad register offset 0x%lx\n", __FUNCTION__, offset);
+ printf("%s: Bad register offset " REG_FMT "\n", __FUNCTION__, offset);
return 0;
}
}
@@ -190,7 +182,7 @@
s->priority[32 + ((offset - IPR32) >> 2)] = value & 0x8000003f;
break;
default:
- printf("%s: Bad register offset 0x%lx\n", __FUNCTION__, offset);
+ printf("%s: Bad register offset " REG_FMT "\n", __FUNCTION__, offset);
return;
}
pxa2xx_pic_update(opaque);
@@ -253,11 +245,11 @@
pxa2xx_pic_mem_write,
};
-struct pxa2xx_pic_state_s *pxa2xx_pic_init(target_phys_addr_t base,
- CPUState *env, int parent_irq, int parent_fiq)
+qemu_irq *pxa2xx_pic_init(target_phys_addr_t base, CPUState *env)
{
struct pxa2xx_pic_state_s *s;
int iomemtype;
+ qemu_irq *qi;
s = (struct pxa2xx_pic_state_s *)
qemu_mallocz(sizeof(struct pxa2xx_pic_state_s));
@@ -273,8 +265,9 @@
s->int_enabled[1] = 0;
s->is_fiq[0] = 0;
s->is_fiq[1] = 0;
- s->handler = pxa2xx_pic_set_irq;
+ qi = qemu_allocate_irqs(pxa2xx_pic_set_irq, s, PXA2XX_PIC_SRCS);
+
/* Enable IC memory-mapped registers access. */
iomemtype = cpu_register_io_memory(0, pxa2xx_pic_readfn,
pxa2xx_pic_writefn, s);
@@ -283,5 +276,5 @@
/* Enable IC coprocessor access. */
cpu_arm_set_cp_io(env, 6, pxa2xx_pic_cp_read, pxa2xx_pic_cp_write, s);
- return s;
+ return qi;
}
Modified: trunk/src/host/qemu-neo1973/hw/pxa2xx_timer.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/pxa2xx_timer.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/pxa2xx_timer.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -14,38 +14,80 @@
#define OSMR2 0x08
#define OSMR3 0x0c
#define OSMR4 0x80
+#define OSMR5 0x84
+#define OSMR6 0x88
+#define OSMR7 0x8c
+#define OSMR8 0x90
+#define OSMR9 0x94
+#define OSMR10 0x98
+#define OSMR11 0x9c
#define OSCR 0x10 /* OS Timer Count */
#define OSCR4 0x40
-#define OMCR4 0xc0
+#define OSCR5 0x44
+#define OSCR6 0x48
+#define OSCR7 0x4c
+#define OSCR8 0x50
+#define OSCR9 0x54
+#define OSCR10 0x58
+#define OSCR11 0x5c
#define OSSR 0x14 /* Timer status register */
#define OWER 0x18
#define OIER 0x1c /* Interrupt enable register 3-0 to E3-E0 */
+#define OMCR4 0xc0 /* OS Match Control registers */
+#define OMCR5 0xc4
+#define OMCR6 0xc8
+#define OMCR7 0xcc
+#define OMCR8 0xd0
+#define OMCR9 0xd4
+#define OMCR10 0xd8
+#define OMCR11 0xdc
+#define OSNR 0x20
#define PXA25X_FREQ 3686400 /* 3.6864 MHz */
#define PXA27X_FREQ 3250000 /* 3.25 MHz */
-typedef struct {
+static int pxa2xx_timer4_freq[8] = {
+ [0] = 0,
+ [1] = 32768,
+ [2] = 1000,
+ [3] = 1,
+ [4] = 1000000,
+ /* [5] is the "Externally supplied clock". Assign if necessary. */
+ [5 ... 7] = 0,
+};
+
+struct pxa2xx_timer0_s {
uint32_t value;
int level;
- int irq;
- void *pic;
+ qemu_irq irq;
QEMUTimer *qtimer;
int num;
void *info;
-} pxa2xx_timer;
+};
+struct pxa2xx_timer4_s {
+ struct pxa2xx_timer0_s tm;
+ int32_t oldclock;
+ int32_t clock;
+ uint64_t lastload;
+ uint32_t freq;
+ uint32_t control;
+};
+
typedef struct {
uint32_t base;
int32_t clock;
int32_t oldclock;
uint64_t lastload;
uint32_t freq;
- pxa2xx_timer timer[4];
+ struct pxa2xx_timer0_s timer[4];
+ struct pxa2xx_timer4_s *tm4;
uint32_t events;
uint32_t irq_enabled;
uint32_t reset3;
CPUState *cpustate;
int64_t qemu_ticks;
+ uint32_t snapshot;
} pxa2xx_timer_info;
static void pxa2xx_timer_update(void *opaque, uint64_t now_qemu)
@@ -65,28 +107,108 @@
}
}
+static void pxa2xx_timer_update4(void *opaque, uint64_t now_qemu, int n)
+{
+ pxa2xx_timer_info *s = (pxa2xx_timer_info *) opaque;
+ uint32_t now_vm;
+ uint64_t new_qemu;
+ static const int counters[8] = { 0, 0, 0, 0, 4, 4, 6, 6 };
+ int counter;
+
+ if (s->tm4[n].control & (1 << 7))
+ counter = n;
+ else
+ counter = counters[n];
+
+ if (!s->tm4[counter].freq) {
+ qemu_del_timer(s->timer[n].qtimer);
+ return;
+ }
+
+ now_vm = s->tm4[counter].clock + muldiv64(now_qemu -
+ s->tm4[counter].lastload,
+ s->tm4[counter].freq, ticks_per_sec);
+
+ new_qemu = now_qemu + muldiv64((uint32_t) (s->tm4[n].tm.value - now_vm),
+ ticks_per_sec, s->tm4[counter].freq);
+ qemu_mod_timer(s->timer[n].qtimer, new_qemu);
+}
+
static uint32_t pxa2xx_timer_read(void *opaque, target_phys_addr_t offset)
{
pxa2xx_timer_info *s = (pxa2xx_timer_info *) opaque;
+ int tm = 0;
offset -= s->base;
switch (offset) {
+ case OSMR3: tm ++;
+ case OSMR2: tm ++;
+ case OSMR1: tm ++;
case OSMR0:
- case OSMR1:
- case OSMR2:
- case OSMR3:
- return s->timer[offset >> 2].value;
+ return s->timer[tm].value;
+ case OSMR11: tm ++;
+ case OSMR10: tm ++;
+ case OSMR9: tm ++;
+ case OSMR8: tm ++;
+ case OSMR7: tm ++;
+ case OSMR6: tm ++;
+ case OSMR5: tm ++;
+ case OSMR4:
+ if (!s->tm4)
+ goto badreg;
+ return s->tm4[tm].tm.value;
case OSCR:
return s->clock + muldiv64(qemu_get_clock(vm_clock) -
s->lastload, s->freq, ticks_per_sec);
+ case OSCR11: tm ++;
+ case OSCR10: tm ++;
+ case OSCR9: tm ++;
+ case OSCR8: tm ++;
+ case OSCR7: tm ++;
+ case OSCR6: tm ++;
+ case OSCR5: tm ++;
+ case OSCR4:
+ if (!s->tm4)
+ goto badreg;
+
+ if ((tm == 9 - 4 || tm == 11 - 4) && (s->tm4[tm].control & (1 << 9))) {
+ if (s->tm4[tm - 1].freq)
+ s->snapshot = s->tm4[tm - 1].clock + muldiv64(
+ qemu_get_clock(vm_clock) -
+ s->tm4[tm - 1].lastload,
+ s->tm4[tm - 1].freq, ticks_per_sec);
+ else
+ s->snapshot = s->tm4[tm - 1].clock;
+ }
+
+ if (!s->tm4[tm].freq)
+ return s->tm4[tm].clock;
+ return s->tm4[tm].clock + muldiv64(qemu_get_clock(vm_clock) -
+ s->tm4[tm].lastload, s->tm4[tm].freq, ticks_per_sec);
case OIER:
return s->irq_enabled;
+ case OSSR: /* Status register */
+ return s->events;
case OWER:
return s->reset3;
+ case OMCR11: tm ++;
+ case OMCR10: tm ++;
+ case OMCR9: tm ++;
+ case OMCR8: tm ++;
+ case OMCR7: tm ++;
+ case OMCR6: tm ++;
+ case OMCR5: tm ++;
+ case OMCR4:
+ if (!s->tm4)
+ goto badreg;
+ return s->tm4[tm].control;
+ case OSNR:
+ return s->snapshot;
default:
- cpu_abort(cpu_single_env,
- "pxa2xx_timer_read: Bad offset %x\n", offset);
+ badreg:
+ cpu_abort(cpu_single_env, "pxa2xx_timer_read: Bad offset "
+ REG_FMT "\n", offset);
}
return 0;
@@ -95,43 +217,110 @@
static void pxa2xx_timer_write(void *opaque, target_phys_addr_t offset,
uint32_t value)
{
- int i;
+ int i, tm = 0;
pxa2xx_timer_info *s = (pxa2xx_timer_info *) opaque;
offset -= s->base;
switch (offset) {
+ case OSMR3: tm ++;
+ case OSMR2: tm ++;
+ case OSMR1: tm ++;
case OSMR0:
- case OSMR1:
- case OSMR2:
- case OSMR3:
- s->timer[offset >> 2].value = value;
+ s->timer[tm].value = value;
pxa2xx_timer_update(s, qemu_get_clock(vm_clock));
break;
+ case OSMR11: tm ++;
+ case OSMR10: tm ++;
+ case OSMR9: tm ++;
+ case OSMR8: tm ++;
+ case OSMR7: tm ++;
+ case OSMR6: tm ++;
+ case OSMR5: tm ++;
+ case OSMR4:
+ if (!s->tm4)
+ goto badreg;
+ s->tm4[tm].tm.value = value;
+ pxa2xx_timer_update4(s, qemu_get_clock(vm_clock), tm);
+ break;
case OSCR:
s->oldclock = s->clock;
s->lastload = qemu_get_clock(vm_clock);
s->clock = value;
pxa2xx_timer_update(s, s->lastload);
break;
+ case OSCR11: tm ++;
+ case OSCR10: tm ++;
+ case OSCR9: tm ++;
+ case OSCR8: tm ++;
+ case OSCR7: tm ++;
+ case OSCR6: tm ++;
+ case OSCR5: tm ++;
+ case OSCR4:
+ if (!s->tm4)
+ goto badreg;
+ s->tm4[tm].oldclock = s->tm4[tm].clock;
+ s->tm4[tm].lastload = qemu_get_clock(vm_clock);
+ s->tm4[tm].clock = value;
+ pxa2xx_timer_update4(s, s->tm4[tm].lastload, tm);
+ break;
case OIER:
- s->irq_enabled = value;
+ s->irq_enabled = value & 0xfff;
break;
case OSSR: /* Status register */
s->events &= ~value;
- for (i = 0; i < 4; i++) {
- if (s->timer[i].level && (value & (1 << i))) {
+ for (i = 0; i < 4; i ++, value >>= 1) {
+ if (s->timer[i].level && (value & 1)) {
s->timer[i].level = 0;
- pic_set_irq_new(s->timer[i].pic, s->timer[i].irq, 0);
+ qemu_irq_lower(s->timer[i].irq);
}
}
+ if (s->tm4) {
+ for (i = 0; i < 8; i ++, value >>= 1)
+ if (s->tm4[i].tm.level && (value & 1))
+ s->tm4[i].tm.level = 0;
+ if (!(s->events & 0xff0))
+ qemu_irq_lower(s->tm4->tm.irq);
+ }
break;
case OWER: /* XXX: Reset on OSMR3 match? */
s->reset3 = value;
break;
+ case OMCR7: tm ++;
+ case OMCR6: tm ++;
+ case OMCR5: tm ++;
+ case OMCR4:
+ if (!s->tm4)
+ goto badreg;
+ s->tm4[tm].control = value & 0x0ff;
+ /* XXX Stop if running (shouldn't happen) */
+ if ((value & (1 << 7)) || tm == 0)
+ s->tm4[tm].freq = pxa2xx_timer4_freq[value & 7];
+ else {
+ s->tm4[tm].freq = 0;
+ pxa2xx_timer_update4(s, qemu_get_clock(vm_clock), tm);
+ }
+ break;
+ case OMCR11: tm ++;
+ case OMCR10: tm ++;
+ case OMCR9: tm ++;
+ case OMCR8: tm += 4;
+ if (!s->tm4)
+ goto badreg;
+ s->tm4[tm].control = value & 0x3ff;
+ /* XXX Stop if running (shouldn't happen) */
+ if ((value & (1 << 7)) || !(tm & 1))
+ s->tm4[tm].freq =
+ pxa2xx_timer4_freq[(value & (1 << 8)) ? 0 : (value & 7)];
+ else {
+ s->tm4[tm].freq = 0;
+ pxa2xx_timer_update4(s, qemu_get_clock(vm_clock), tm);
+ }
+ break;
default:
- cpu_abort(cpu_single_env,
- "pxa2xx_timer_write: Bad offset %x\n", offset);
+ badreg:
+ cpu_abort(cpu_single_env, "pxa2xx_timer_write: Bad offset "
+ REG_FMT "\n", offset);
}
}
@@ -149,12 +338,13 @@
static void pxa2xx_timer_tick(void *opaque)
{
- pxa2xx_timer *t = (pxa2xx_timer *) opaque;
+ struct pxa2xx_timer0_s *t = (struct pxa2xx_timer0_s *) opaque;
pxa2xx_timer_info *i = (pxa2xx_timer_info *) t->info;
if (i->irq_enabled & (1 << t->num)) {
t->level = 1;
- pic_set_irq_new(t->pic, t->irq, 1);
+ i->events |= 1 << t->num;
+ qemu_irq_raise(t->irq);
}
if (t->num == 3)
@@ -164,8 +354,20 @@
}
}
+static void pxa2xx_timer_tick4(void *opaque)
+{
+ struct pxa2xx_timer4_s *t = (struct pxa2xx_timer4_s *) opaque;
+ pxa2xx_timer_info *i = (pxa2xx_timer_info *) t->tm.info;
+
+ pxa2xx_timer_tick(&t->tm);
+ if (t->control & (1 << 3))
+ t->clock = 0;
+ if (t->control & (1 << 6))
+ pxa2xx_timer_update4(i, qemu_get_clock(vm_clock), t->tm.num - 4);
+}
+
static pxa2xx_timer_info *pxa2xx_timer_init(target_phys_addr_t base,
- void *pic, int irq, CPUState *cpustate)
+ qemu_irq *irqs, CPUState *cpustate)
{
int i;
int iomemtype;
@@ -182,8 +384,7 @@
for (i = 0; i < 4; i ++) {
s->timer[i].value = 0;
- s->timer[i].irq = irq + i;
- s->timer[i].pic = pic;
+ s->timer[i].irq = irqs[i];
s->timer[i].info = s;
s->timer[i].num = i;
s->timer[i].level = 0;
@@ -198,15 +399,30 @@
}
void pxa25x_timer_init(target_phys_addr_t base,
- void *pic, int irq, CPUState *cpustate)
+ qemu_irq *irqs, CPUState *cpustate)
{
- pxa2xx_timer_info *s = pxa2xx_timer_init(base, pic, irq, cpustate);
+ pxa2xx_timer_info *s = pxa2xx_timer_init(base, irqs, cpustate);
s->freq = PXA25X_FREQ;
+ s->tm4 = 0;
}
void pxa27x_timer_init(target_phys_addr_t base,
- void *pic, int irq, CPUState *cpustate)
+ qemu_irq *irqs, qemu_irq irq4, CPUState *cpustate)
{
- pxa2xx_timer_info *s = pxa2xx_timer_init(base, pic, irq, cpustate);
+ pxa2xx_timer_info *s = pxa2xx_timer_init(base, irqs, cpustate);
+ int i;
s->freq = PXA27X_FREQ;
+ s->tm4 = (struct pxa2xx_timer4_s *) qemu_mallocz(8 *
+ sizeof(struct pxa2xx_timer4_s));
+ for (i = 0; i < 8; i ++) {
+ s->tm4[i].tm.value = 0;
+ s->tm4[i].tm.irq = irq4;
+ s->tm4[i].tm.info = s;
+ s->tm4[i].tm.num = i + 4;
+ s->tm4[i].tm.level = 0;
+ s->tm4[i].freq = 0;
+ s->tm4[i].control = 0x0;
+ s->tm4[i].tm.qtimer = qemu_new_timer(vm_clock,
+ pxa2xx_timer_tick4, &s->tm4[i]);
+ }
}
Modified: trunk/src/host/qemu-neo1973/hw/realview.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/realview.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/realview.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -1,7 +1,7 @@
/*
* ARM RealView Baseboard System emulation.
*
- * Copyright (c) 2006 CodeSourcery.
+ * Copyright (c) 2006-2007 CodeSourcery.
* Written by Paul Brook
*
* This code is licenced under the GPL.
@@ -15,10 +15,10 @@
static void realview_init(int ram_size, int vga_ram_size, int boot_device,
DisplayState *ds, const char **fd_filename, int snapshot,
const char *kernel_filename, const char *kernel_cmdline,
- const char *initrd_filename)
+ const char *initrd_filename, const char *cpu_model)
{
CPUState *env;
- void *pic;
+ qemu_irq *pic;
void *scsi_hba;
PCIBus *pci_bus;
NICInfo *nd;
@@ -26,8 +26,9 @@
int done_smc = 0;
env = cpu_init();
- cpu_arm_set_model(env, ARM_CPUID_ARM926);
- //cpu_arm_set_model(env, ARM_CPUID_ARM11MPCORE);
+ if (!cpu_model)
+ cpu_model = "arm926";
+ cpu_arm_set_model(env, cpu_model);
/* ??? RAM shoud repeat to fill physical memory space. */
/* SDRAM at address zero. */
cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
@@ -37,23 +38,25 @@
/* ??? The documentation says GIC1 is nFIQ and either GIC2 or GIC3
is nIRQ (there are inconsistencies). However Linux 2.6.17 expects
GIC1 to be nIRQ and ignores all the others, so do that for now. */
- pic = arm_gic_init(0x10040000, pic, ARM_PIC_CPU_IRQ);
- pl050_init(0x10006000, pic, 20, 0);
- pl050_init(0x10007000, pic, 21, 1);
+ pic = arm_gic_init(0x10040000, pic[ARM_PIC_CPU_IRQ]);
+ pl050_init(0x10006000, pic[20], 0);
+ pl050_init(0x10007000, pic[21], 1);
- pl011_init(0x10009000, pic, 12, serial_hds[0]);
- pl011_init(0x1000a000, pic, 13, serial_hds[1]);
- pl011_init(0x1000b000, pic, 14, serial_hds[2]);
- pl011_init(0x1000c000, pic, 15, serial_hds[3]);
+ pl011_init(0x10009000, pic[12], serial_hds[0]);
+ pl011_init(0x1000a000, pic[13], serial_hds[1]);
+ pl011_init(0x1000b000, pic[14], serial_hds[2]);
+ pl011_init(0x1000c000, pic[15], serial_hds[3]);
/* DMA controller is optional, apparently. */
- pl080_init(0x10030000, pic, 24, 2);
+ pl080_init(0x10030000, pic[24], 2);
- sp804_init(0x10011000, pic, 4);
- sp804_init(0x10012000, pic, 5);
+ sp804_init(0x10011000, pic[4]);
+ sp804_init(0x10012000, pic[5]);
- pl110_init(ds, 0x10020000, pic, 23, 1);
+ pl110_init(ds, 0x10020000, pic[23], 1);
+ pl181_init(0x10005000, sd_bdrv, pic[17], pic[18]);
+
pci_bus = pci_vpb_init(pic, 48, 1);
if (usb_enabled) {
usb_ohci_init_pci(pci_bus, 3, -1);
@@ -69,9 +72,9 @@
if (!nd->model)
nd->model = done_smc ? "rtl8139" : "smc91c111";
if (strcmp(nd->model, "smc91c111") == 0) {
- smc91c111_init(nd, 0x4e000000, pic, 28);
+ smc91c111_init(nd, 0x4e000000, pic[28]);
} else {
- pci_nic_init(pci_bus, nd);
+ pci_nic_init(pci_bus, nd, -1);
}
}
@@ -127,7 +130,7 @@
/* 0x68000000 PCI mem 1. */
/* 0x6c000000 PCI mem 2. */
- arm_load_kernel(ram_size, kernel_filename, kernel_cmdline,
+ arm_load_kernel(env, ram_size, kernel_filename, kernel_cmdline,
initrd_filename, 0x33b, 0x0);
}
Modified: trunk/src/host/qemu-neo1973/hw/rtl8139.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/rtl8139.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/rtl8139.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -461,7 +461,6 @@
uint16_t CpCmd;
uint8_t TxThresh;
- int irq;
PCIDevice *pci_dev;
VLANClientState *vc;
uint8_t macaddr[6];
@@ -685,16 +684,10 @@
int isr;
isr = (s->IntrStatus & s->IntrMask) & 0xffff;
- DEBUG_PRINT(("RTL8139: Set IRQ line %d to %d (%04x %04x)\n",
- s->irq, isr ? 1 : 0, s->IntrStatus, s->IntrMask));
+ DEBUG_PRINT(("RTL8139: Set IRQ to %d (%04x %04x)\n",
+ isr ? 1 : 0, s->IntrStatus, s->IntrMask));
- if (s->irq == 16) {
- /* PCI irq */
- pci_set_irq(s->pci_dev, 0, (isr != 0));
- } else {
- /* ISA irq */
- pic_set_irq(s->irq, (isr != 0));
- }
+ qemu_set_irq(s->pci_dev->irq[0], (isr != 0));
}
#define POLYNOMIAL 0x04c11db6
@@ -1192,8 +1185,11 @@
s->eeprom.contents[1] = 0x10ec;
s->eeprom.contents[2] = 0x8139;
#endif
- memcpy(&s->eeprom.contents[7], s->macaddr, 6);
+ s->eeprom.contents[7] = s->macaddr[0] | s->macaddr[1] << 8;
+ s->eeprom.contents[8] = s->macaddr[2] | s->macaddr[3] << 8;
+ s->eeprom.contents[9] = s->macaddr[4] | s->macaddr[5] << 8;
+
/* mark all status registers as owned by host */
for (i = 0; i < 4; ++i)
{
@@ -2455,12 +2451,12 @@
{
DEBUG_PRINT(("RTL8139: TxAddr write offset=0x%x val=0x%08x\n", txAddrOffset, val));
- s->TxAddr[txAddrOffset/4] = le32_to_cpu(val);
+ s->TxAddr[txAddrOffset/4] = val;
}
static uint32_t rtl8139_TxAddr_read(RTL8139State *s, uint32_t txAddrOffset)
{
- uint32_t ret = cpu_to_le32(s->TxAddr[txAddrOffset/4]);
+ uint32_t ret = s->TxAddr[txAddrOffset/4];
DEBUG_PRINT(("RTL8139: TxAddr read offset=0x%x val=0x%08x\n", txAddrOffset, ret));
@@ -3170,7 +3166,8 @@
qemu_put_be16s(f, &s->CpCmd);
qemu_put_8s(f, &s->TxThresh);
- qemu_put_be32s(f, &s->irq);
+ i = 0;
+ qemu_put_be32s(f, &i); /* unused. */
qemu_put_buffer(f, s->macaddr, 6);
qemu_put_be32s(f, &s->rtl8139_mmio_io_addr);
@@ -3264,7 +3261,7 @@
qemu_get_be16s(f, &s->CpCmd);
qemu_get_8s(f, &s->TxThresh);
- qemu_get_be32s(f, &s->irq);
+ qemu_get_be32s(f, &i); /* unused. */
qemu_get_buffer(f, s->macaddr, 6);
qemu_get_be32s(f, &s->rtl8139_mmio_io_addr);
@@ -3409,7 +3406,7 @@
}
#endif /* RTL8139_ONBOARD_TIMER */
-void pci_rtl8139_init(PCIBus *bus, NICInfo *nd)
+void pci_rtl8139_init(PCIBus *bus, NICInfo *nd, int devfn)
{
PCIRTL8139State *d;
RTL8139State *s;
@@ -3417,7 +3414,7 @@
d = (PCIRTL8139State *)pci_register_device(bus,
"RTL8139", sizeof(PCIRTL8139State),
- -1,
+ devfn,
NULL, NULL);
pci_conf = d->dev.config;
pci_conf[0x00] = 0xec; /* Realtek 8139 */
@@ -3444,7 +3441,6 @@
pci_register_io_region(&d->dev, 1, 0x100,
PCI_ADDRESS_SPACE_MEM, rtl8139_mmio_map);
- s->irq = 16; /* PCI interrupt */
s->pci_dev = (PCIDevice *)d;
memcpy(s->macaddr, nd->macaddr, 6);
rtl8139_reset(s);
Modified: trunk/src/host/qemu-neo1973/hw/s3c.h
===================================================================
--- trunk/src/host/qemu-neo1973/hw/s3c.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/s3c.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -52,6 +52,8 @@
# define S3C_PICS_ERR2 40
# define S3C_PICS_TC 41
# define S3C_PICS_ADC 42
+
+# define S3C_PIC_MAX 43
/* External interrupt numbers */
# define S3C_EINT(n) ((n >= 8) ? (6 << 5) | (n - 8) : (5 << 5) | n)
@@ -77,6 +79,8 @@
# define S3C_RQ_USB_EP3 0x24
# define S3C_RQ_USB_EP4 0x34
+# define S3C_RQ_MAX 0x35
+
/* I/O port numbers */
# define S3C_GP(b, n) (((b) << 5) | n)
# define S3C_GPA(n) S3C_GP(0, n)
@@ -87,6 +91,7 @@
# define S3C_GPF(n) S3C_GP(5, n)
# define S3C_GPG(n) S3C_GP(6, n)
# define S3C_GPH(n) S3C_GP(7, n)
+# define S3C_GP_MAX S3C_GP(8, 0)
# define S3C_RAM_BASE 0x30000000
# define S3C_SRAM_BASE 0x40000000
@@ -97,51 +102,54 @@
/* s3c2410.c */
struct s3c_pic_state_s;
-struct s3c_pic_state_s *s3c_pic_init(target_phys_addr_t base, CPUState *env);
+struct s3c_pic_state_s *s3c_pic_init(target_phys_addr_t base,
+ qemu_irq *arm_pic);
+qemu_irq *s3c_pic_get(struct s3c_pic_state_s *s);
struct s3c_dma_state_s;
-struct s3c_dma_state_s *s3c_dma_init(target_phys_addr_t base, void *pic);
+struct s3c_dma_state_s *s3c_dma_init(target_phys_addr_t base, qemu_irq *pic);
+qemu_irq *s3c_dma_get(struct s3c_dma_state_s *s);
struct s3c_timers_state_s;
struct s3c_timers_state_s *s3c_timers_init(target_phys_addr_t base,
- void *pic, void *dma);
+ qemu_irq *pic, qemu_irq *dma);
void s3c_timers_cmp_handler_set(void *opaque, int line,
gpio_handler_t handler, void *cmp_opaque);
struct s3c_uart_state_s;
struct s3c_uart_state_s *s3c_uart_init(target_phys_addr_t base,
- void *pic, void *dma, int irq[], int drq[]);
+ qemu_irq *irqs, qemu_irq *dma);
void s3c_uart_attach(struct s3c_uart_state_s *s, CharDriverState *chr);
struct s3c_adc_state_s;
-struct s3c_adc_state_s *s3c_adc_init(target_phys_addr_t base, void *pic);
+struct s3c_adc_state_s *s3c_adc_init(target_phys_addr_t base, qemu_irq irq,
+ qemu_irq tcirq);
struct s3c_i2c_state_s;
-struct s3c_i2c_state_s *s3c_i2c_init(target_phys_addr_t base, void *pic);
-struct i2c_master_s *s3c_i2c_master(struct s3c_i2c_state_s *s);
+struct s3c_i2c_state_s *s3c_i2c_init(target_phys_addr_t base, qemu_irq irq);
+i2c_bus *s3c_i2c_bus(struct s3c_i2c_state_s *s);
struct s3c_i2s_state_s;
-struct s3c_i2s_state_s *s3c_i2s_init(target_phys_addr_t base, void *dma);
+struct s3c_i2s_state_s *s3c_i2s_init(target_phys_addr_t base, qemu_irq *dma);
/* s3c24xx_gpio.c */
struct s3c_gpio_state_s;
-struct s3c_gpio_state_s *s3c_gpio_init(target_phys_addr_t base, void *pic);
-void s3c_gpio_set(void *opaque, int line, int level);
-void s3c_gpio_handler_set(struct s3c_gpio_state_s *s, int line,
- gpio_handler_t handler, void *opaque);
+struct s3c_gpio_state_s *s3c_gpio_init(target_phys_addr_t base, qemu_irq *pic);
+qemu_irq *s3c_gpio_in_get(struct s3c_gpio_state_s *s);
+void s3c_gpio_out_set(struct s3c_gpio_state_s *s, int line, qemu_irq handler);
void s3c_gpio_setpwrstat(struct s3c_gpio_state_s *s, int stat);
void s3c_gpio_reset(struct s3c_gpio_state_s *s);
/* s3c24xx_lcd.c */
struct s3c_lcd_state_s;
struct s3c_lcd_state_s *s3c_lcd_init(target_phys_addr_t base, DisplayState *ds,
- void *pic);
+ qemu_irq irq);
void s3c_lcd_reset(struct s3c_lcd_state_s *s);
/* s3c24xx_mmci.c */
struct s3c_mmci_state_s;
struct s3c_mmci_state_s *s3c_mmci_init(target_phys_addr_t base,
- void *pic, void *dma);
+ qemu_irq irq, qemu_irq *dma);
void s3c_mmci_handlers(struct s3c_mmci_state_s *s, void *opaque,
void (*readonly_cb)(void *, int),
void (*coverswitch_cb)(void *, int));
@@ -149,26 +157,28 @@
/* s3c24xx_rtc.c */
struct s3c_rtc_state_s;
-struct s3c_rtc_state_s *s3c_rtc_init(target_phys_addr_t base, void *pic);
+struct s3c_rtc_state_s *s3c_rtc_init(target_phys_addr_t base, qemu_irq irq);
void s3c_rtc_reset(struct s3c_rtc_state_s *s);
/* s3c24xx_udc.c */
struct s3c_udc_state_s;
-struct s3c_udc_state_s *s3c_udc_init(target_phys_addr_t base, void *pic,
- void *dma);
+struct s3c_udc_state_s *s3c_udc_init(target_phys_addr_t base, qemu_irq irq,
+ qemu_irq *dma);
void s3c_udc_reset(struct s3c_udc_state_s *s);
/* s3c2410.c */
struct s3c_spi_state_s;
-struct s3c_spi_state_s *s3c_spi_init(target_phys_addr_t base, void *pic,
- void *dma, struct s3c_gpio_state_s *gpio);
+struct s3c_spi_state_s *s3c_spi_init(target_phys_addr_t base,
+ qemu_irq irq0, qemu_irq drq0, qemu_irq irq1, qemu_irq drq1,
+ struct s3c_gpio_state_s *gpio);
void s3c_spi_attach(struct s3c_spi_state_s *s, int ch,
uint8_t (*txrx)(void *opaque, uint8_t value),
uint8_t (*btxrx)(void *opaque, uint8_t value), void *opaque);
struct s3c_state_s {
CPUState *env;
- uint32_t free_ram_start;/* XXX */
+ qemu_irq *irq;
+ qemu_irq *drq;
struct s3c_pic_state_s *pic;
struct s3c_dma_state_s *dma;
struct s3c_gpio_state_s *io;
@@ -202,14 +212,12 @@
/* s3c2410.c */
void s3c2410_reset(struct s3c_state_s *s);
-struct s3c_state_s *s3c2410_init(DisplayState *ds);
+struct s3c_state_s *s3c2410_init(unsigned int sdram_size, DisplayState *ds);
void s3c_nand_register(struct s3c_state_s *s, struct nand_flash_s *chip);
-typedef void (*s3c_pic_handler_t)(void *opaque, int irq, int level);
struct s3c_i2s_state_s { /* XXX move to .c */
target_phys_addr_t base;
- void *pic;
- void *dma;
+ qemu_irq *dma;
void (*data_req)(void *, int, int);
uint16_t control;
Modified: trunk/src/host/qemu-neo1973/hw/s3c2410.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/s3c2410.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/s3c2410.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -10,9 +10,9 @@
/* Interrupt controller */
struct s3c_pic_state_s {
- s3c_pic_handler_t handler;
- CPUState *cpu;
target_phys_addr_t base;
+ qemu_irq *parent_pic;
+ qemu_irq *irqs;
uint32_t srcpnd;
uint32_t intpnd;
@@ -26,15 +26,10 @@
static void s3c_pic_update(struct s3c_pic_state_s *s)
{
- if (s->srcpnd & ~s->intmsk & s->intmod)
- cpu_interrupt(s->cpu, CPU_INTERRUPT_FIQ);
- else
- cpu_reset_interrupt(s->cpu, CPU_INTERRUPT_FIQ);
-
- if (s->intpnd & ~s->intmsk & ~s->intmod)
- cpu_interrupt(s->cpu, CPU_INTERRUPT_HARD);
- else
- cpu_reset_interrupt(s->cpu, CPU_INTERRUPT_HARD);
+ qemu_set_irq(s->parent_pic[ARM_PIC_CPU_FIQ],
+ s->srcpnd & ~s->intmsk & s->intmod);
+ qemu_set_irq(s->parent_pic[ARM_PIC_CPU_IRQ],
+ s->intpnd & ~s->intmsk & ~s->intmod);
}
static const uint32_t s3c_arbmsk[6] = {
@@ -246,15 +241,16 @@
s3c_pic_write,
};
-struct s3c_pic_state_s *s3c_pic_init(target_phys_addr_t base, CPUState *env)
+struct s3c_pic_state_s *s3c_pic_init(target_phys_addr_t base,
+ qemu_irq *arm_pic)
{
int iomemtype;
struct s3c_pic_state_s *s = (struct s3c_pic_state_s *)
qemu_mallocz(sizeof(struct s3c_pic_state_s));
s->base = base;
- s->cpu = env;
- s->handler = s3c_pic_set_irq;
+ s->parent_pic = arm_pic;
+ s->irqs = qemu_allocate_irqs(s3c_pic_set_irq, s, S3C_PIC_MAX);
s3c_pic_reset(s);
@@ -265,6 +261,11 @@
return s;
}
+qemu_irq *s3c_pic_get(struct s3c_pic_state_s *s)
+{
+ return s->irqs;
+}
+
/* Memory controller */
#define S3C_BWSCON 0x00 /* Bus Width & Wait Control register */
#define S3C_BANKCON0 0x04 /* Bank 0 Control register */
@@ -540,12 +541,11 @@
#define S3C_DMA_CH_N 4
struct s3c_dma_ch_state_s;
-struct s3c_dma_state_s {
- s3c_pic_handler_t handler; /* Modelled as an interrupt controller */
+struct s3c_dma_state_s { /* Modelled as an interrupt controller */
target_phys_addr_t base;
- void *pic;
+ qemu_irq *drqs;
struct s3c_dma_ch_state_s {
- int intr;
+ qemu_irq intr;
int curr_tc;
int req;
int running;
@@ -591,7 +591,7 @@
}
ch->running = 0;
if (!ch->curr_tc && (ch->con & (1 << 29))) /* INT */
- pic_set_irq_new(s->pic, ch->intr, 1);
+ qemu_irq_raise(ch->intr);
if (ch->con & (1 << 22)) { /* RELOAD */
if (!(ch->con & (1 << 23))) { /* SWHW_SEL */
@@ -741,19 +741,18 @@
s3c_dma_write,
};
-struct s3c_dma_state_s *s3c_dma_init(target_phys_addr_t base, void *pic)
+struct s3c_dma_state_s *s3c_dma_init(target_phys_addr_t base, qemu_irq *pic)
{
int iomemtype;
struct s3c_dma_state_s *s = (struct s3c_dma_state_s *)
qemu_mallocz(sizeof(struct s3c_dma_state_s));
s->base = base;
- s->pic = pic;
- s->ch[0].intr = S3C_PIC_DMA0;
- s->ch[1].intr = S3C_PIC_DMA1;
- s->ch[2].intr = S3C_PIC_DMA2;
- s->ch[3].intr = S3C_PIC_DMA3;
- s->handler = s3c_dma_dreq;
+ s->ch[0].intr = pic[0];
+ s->ch[1].intr = pic[1];
+ s->ch[2].intr = pic[2];
+ s->ch[3].intr = pic[3];
+ s->drqs = qemu_allocate_irqs(s3c_dma_dreq, s, S3C_RQ_MAX);
s3c_dma_reset(s);
@@ -764,12 +763,16 @@
return s;
}
+qemu_irq *s3c_dma_get(struct s3c_dma_state_s *s)
+{
+ return s->drqs;
+}
+
/* PWM timers controller */
struct s3c_timer_state_s;
struct s3c_timers_state_s {
target_phys_addr_t base;
- void *pic;
- void *dma;
+ qemu_irq *dma;
DisplayState *ds;
struct s3c_timer_state_s {
QEMUTimer *t;
@@ -779,7 +782,7 @@
uint32_t divider;
uint16_t count;
int64_t reload;
- int irq;
+ qemu_irq irq;
gpio_handler_t cmp_cb;
void *cmp_opaque;
} timer[5];
@@ -855,11 +858,11 @@
return;
if (((s->config[1] >> 20) & 0xf) == t->n + 1) {
- pic_set_irq_new(s->dma, S3C_RQ_TIMER0, 1); /* TODO */
- pic_set_irq_new(s->dma, S3C_RQ_TIMER1, 1);
- pic_set_irq_new(s->dma, S3C_RQ_TIMER2, 1);
+ qemu_irq_raise(s->dma[S3C_RQ_TIMER0]); /* TODO */
+ qemu_irq_raise(s->dma[S3C_RQ_TIMER1]);
+ qemu_irq_raise(s->dma[S3C_RQ_TIMER2]);
} else
- pic_set_irq_new(s->pic, t->irq, 1);
+ qemu_irq_raise(t->irq);
t->running = 0;
t->count = 0;
@@ -994,14 +997,13 @@
};
struct s3c_timers_state_s *s3c_timers_init(target_phys_addr_t base,
- void *pic, void *dma)
+ qemu_irq *pic, qemu_irq *dma)
{
int i, iomemtype;
struct s3c_timers_state_s *s = (struct s3c_timers_state_s *)
qemu_mallocz(sizeof(struct s3c_timers_state_s));
s->base = base;
- s->pic = pic;
s->dma = dma;
s3c_timers_reset(s);
@@ -1012,12 +1014,8 @@
s->timer[i].s = s;
s->timer[i].n = i;
s->timer[i].cmp_cb = 0;
+ s->timer[i].irq = pic[i];
}
- s->timer[0].irq = S3C_PIC_TIMER0;
- s->timer[1].irq = S3C_PIC_TIMER1;
- s->timer[2].irq = S3C_PIC_TIMER2;
- s->timer[3].irq = S3C_PIC_TIMER3;
- s->timer[4].irq = S3C_PIC_TIMER4;
iomemtype = cpu_register_io_memory(0, s3c_timers_readfn,
s3c_timers_writefn, s);
@@ -1041,10 +1039,8 @@
/* UART */
struct s3c_uart_state_s {
target_phys_addr_t base;
- void *pic;
- void *dma;
- int *irq;
- int *drq;
+ qemu_irq *irq;
+ qemu_irq *dma;
uint8_t data;
uint8_t rxfifo[16];
int rxstart;
@@ -1108,7 +1104,7 @@
{
s->errstat |= err;
if (s->control & (1 << 6))
- pic_set_irq_new(s->pic, s->irq[2], 1);
+ qemu_irq_raise(s->irq[2]);
}
static void s3c_uart_full(struct s3c_uart_state_s *s)
@@ -1119,11 +1115,11 @@
switch ((s->control >> 0) & 3) { /* ReceiveMode */
case 1:
- pic_set_irq_new(s->pic, s->irq[0], 1);
+ qemu_irq_raise(s->irq[0]);
break;
case 2:
case 3:
- pic_set_irq_new(s->dma, s->drq[0], 1);
+ qemu_irq_raise(s->dma[0]);
break;
}
}
@@ -1132,11 +1128,11 @@
{
switch ((s->control >> 2) & 3) { /* TransmitMode */
case 1:
- pic_set_irq_new(s->pic, s->irq[1], 1);
+ qemu_irq_raise(s->irq[1]);
break;
case 2:
case 3:
- pic_set_irq_new(s->dma, s->drq[0], 1);
+ qemu_irq_raise(s->dma[0]);
break;
}
}
@@ -1176,6 +1172,11 @@
s3c_uart_full(s);
}
+/* S3C2410 UART doesn't seem to understand break conditions. */
+static void s3c_uart_event(void *opaque, int event)
+{
+}
+
#define S3C_ULCON 0x00 /* UART Line Control register */
#define S3C_UCON 0x04 /* UART Control register */
#define S3C_UFCON 0x08 /* UART FIFO Control register */
@@ -1296,17 +1297,15 @@
};
struct s3c_uart_state_s *s3c_uart_init(target_phys_addr_t base,
- void *pic, void *dma, int irq[], int drq[])
+ qemu_irq *irqs, qemu_irq *dma)
{
int iomemtype;
struct s3c_uart_state_s *s = (struct s3c_uart_state_s *)
qemu_mallocz(sizeof(struct s3c_uart_state_s));
s->base = base;
- s->pic = pic;
+ s->irq = irqs;
s->dma = dma;
- s->irq = irq;
- s->drq = drq;
s3c_uart_reset(s);
@@ -1323,14 +1322,15 @@
cpu_abort(cpu_single_env, "%s: Too many devices\n", __FUNCTION__);
s->chr[s->chr_num ++] = chr;
- qemu_chr_add_read_handler(chr, s3c_uart_is_empty, s3c_uart_rx, s);
- /* S3C2410 UART doesn't seem to understand break conditions. */
+ qemu_chr_add_handlers(chr, s3c_uart_is_empty,
+ s3c_uart_rx, s3c_uart_event, s);
}
/* ADC & Touchscreen interface */
struct s3c_adc_state_s {
target_phys_addr_t base;
- void *pic;
+ qemu_irq irq;
+ qemu_irq tcirq;
QEMUTimer *convt;
QEMUTimer *tst;
int x;
@@ -1371,7 +1371,7 @@
struct s3c_adc_state_s *s = (struct s3c_adc_state_s *) opaque;
s->xdata = s->input[s->in_idx] & 0x3ff;
s->control |= 1 << 15;
- pic_set_irq_new(s->pic, S3C_PICS_ADC, 1);
+ qemu_irq_raise(s->irq);
}
static void s3c_adc_tick(void *opaque)
@@ -1379,13 +1379,13 @@
struct s3c_adc_state_s *s = (struct s3c_adc_state_s *) opaque;
if (s->down) {
if ((s->ts & 3) == 3 && s->enable)
- pic_set_irq_new(s->pic, S3C_PICS_TC, 1);
+ qemu_irq_raise(s->tcirq);
else if (s->enable && ((s->ts & (1 << 2)) || (s->ts & 3))) {
s->xdata = (s->x >> 5) | (1 << 14) | ((s->ts & 3) << 12);
s->ydata = (s->y >> 5) | (1 << 14) | ((s->ts & 3) << 12);
s->xdata ^= s->noise >> 1;
s->ydata ^= s->noise >> 2;
- pic_set_irq_new(s->pic, S3C_PICS_ADC, 1);
+ qemu_irq_raise(s->irq);
s->noise ++;
s->noise &= 7;
}
@@ -1476,14 +1476,16 @@
s3c_adc_write,
};
-struct s3c_adc_state_s *s3c_adc_init(target_phys_addr_t base, void *pic)
+struct s3c_adc_state_s *s3c_adc_init(target_phys_addr_t base, qemu_irq irq,
+ qemu_irq tcirq)
{
int iomemtype;
struct s3c_adc_state_s *s = (struct s3c_adc_state_s *)
qemu_mallocz(sizeof(struct s3c_adc_state_s));
s->base = base;
- s->pic = pic;
+ s->irq = irq;
+ s->tcirq = tcirq;
s->convt = qemu_new_timer(vm_clock, s3c_adc_done, s);
s->tst = qemu_new_timer(vm_clock, s3c_adc_tick, s);
@@ -1502,15 +1504,15 @@
/* IIC-bus serial interface */
struct s3c_i2c_state_s {
+ i2c_slave slave;
+ i2c_bus *bus;
target_phys_addr_t base;
- void *pic;
- struct i2c_master_s master;
- struct i2c_slave_s slave;
+ qemu_irq irq;
uint8_t control;
uint8_t status;
uint8_t data;
- uint8_t address;
+ uint8_t addy;
int busy;
int newstart;
};
@@ -1519,7 +1521,7 @@
{
s->control |= 1 << 4;
if (s->control & (1 << 5))
- pic_set_irq_new(s->pic, S3C_PIC_IIC, 1);
+ qemu_irq_raise(s->irq);
}
static void s3c_i2c_reset(struct s3c_i2c_state_s *s)
@@ -1530,64 +1532,95 @@
s->newstart = 0;
}
-static void s3c_i2c_start(void *opaque, int dir)
+static void s3c_i2c_event(i2c_slave *i2c, enum i2c_event event)
{
- struct s3c_i2c_state_s *s = (struct s3c_i2c_state_s *) opaque;
+ struct s3c_i2c_state_s *s = (struct s3c_i2c_state_s *) i2c;
if (!(s->status & (1 << 4)))
return;
- s->status &= ~(1 << 2);
- s3c_i2c_irq(s);
+ switch (event) {
+ case I2C_START_RECV:
+ case I2C_START_SEND:
+ s->status |= 1 << 2;
+ s3c_i2c_irq(s);
+ break;
+ case I2C_FINISH:
+ s->status &= ~6;
+ break;
+ case I2C_NACK:
+ s->status |= 1 << 0;
+ break;
+ default:
+ break;
+ }
}
-static void s3c_i2c_stop(void *opaque)
+static int s3c_i2c_tx(i2c_slave *i2c, uint8_t data)
{
- struct s3c_i2c_state_s *s = (struct s3c_i2c_state_s *) opaque;
- s->status &= ~(1 << 2);
+ struct s3c_i2c_state_s *s = (struct s3c_i2c_state_s *) i2c;
+ if (!(s->status & (1 << 4)))
+ return 1;
+
+ if ((s->status >> 6) == 0)
+ s->data = data; /* TODO */
+ s->status &= ~(1 << 0);
+ s3c_i2c_irq(s);
+
+ return !(s->control & (1 << 7));
}
-static int s3c_i2c_tx(void *opaque, uint8_t *message, int len)
+static int s3c_i2c_rx(i2c_slave *i2c)
{
- struct s3c_i2c_state_s *s = (struct s3c_i2c_state_s *) opaque;
+ struct s3c_i2c_state_s *s = (struct s3c_i2c_state_s *) i2c;
if (!(s->status & (1 << 4)))
return 1;
- if (len) {
- if ((s->status >> 6) == 0)
- s->master.data = message[0]; /* TODO */
- else if ((s->status >> 6) == 1)
- message[0] = s->master.data; /* TODO */
+ if ((s->status >> 6) == 1) {
+ s->status &= ~(1 << 0);
+ s3c_i2c_irq(s);
+ return s->data;
}
- s3c_i2c_irq(s);
- return !(s->control & (1 << 7));
+ return 0x00;
}
static void s3c_master_work(void *opaque)
{
struct s3c_i2c_state_s *s = (struct s3c_i2c_state_s *) opaque;
- int start = 0;
+ int start = 0, stop = 0, ack = 1;
if (s->control & (1 << 4)) /* Interrupt pending */
return;
if ((s->status & 0x90) != 0x90) /* Master */
return;
+ stop = ~s->status & (1 << 5);
if (s->newstart && s->status & (1 << 5)) { /* START */
s->busy = 1;
start = 1;
- s->master.data |= (~s->status >> 6) & 1;
}
s->newstart = 0;
if (!s->busy)
return;
- i2c_master_submit(&s->master, start, (~s->status >> 4) & 2);
+ if (start)
+ ack = !i2c_start_transfer(s->bus, s->data >> 1, (~s->status >> 6) & 1);
+ else if (stop)
+ i2c_end_transfer(s->bus);
+ else if (s->status & (1 << 6))
+ ack = !i2c_send(s->bus, s->data);
+ else {
+ s->data = i2c_recv(s->bus);
+
+ if (!(s->control & (1 << 7))) /* ACK */
+ i2c_nack(s->bus);
+ }
+
if (!(s->status & (1 << 5))) {
s->busy = 0;
return;
}
s->status &= ~1;
- s->status |= !s->master.ack;
- if (!s->master.ack)
+ s->status |= !ack;
+ if (!ack)
s->busy = 0;
s3c_i2c_irq(s);
}
@@ -1608,9 +1641,9 @@
case S3C_IICSTAT:
return s->status & ~(1 << 5); /* Busy signal */
case S3C_IICADD:
- return s->slave.address;
+ return s->addy;
case S3C_IICDS:
- return s->master.data;
+ return s->data;
default:
printf("%s: Bad register 0x%lx\n", __FUNCTION__, addr);
break;
@@ -1640,12 +1673,12 @@
break;
case S3C_IICADD:
- if (s->master.bus)
- i2c_slave_attach(s->master.bus, value & 0x7f, &s->slave);
+ s->addy = value & 0x7f;
+ i2c_set_slave_address(&s->slave, s->addy);
break;
case S3C_IICDS:
- s->master.data = value & 0xff;
+ s->data = value & 0xff;
break;
default:
@@ -1665,18 +1698,18 @@
s3c_i2c_write,
};
-struct s3c_i2c_state_s *s3c_i2c_init(target_phys_addr_t base, void *pic)
+struct s3c_i2c_state_s *s3c_i2c_init(target_phys_addr_t base, qemu_irq irq)
{
int iomemtype;
struct s3c_i2c_state_s *s = (struct s3c_i2c_state_s *)
qemu_mallocz(sizeof(struct s3c_i2c_state_s));
s->base = base;
- s->pic = pic;
- s->slave.tx = s3c_i2c_tx;
- s->slave.start = s3c_i2c_start;
- s->slave.stop = s3c_i2c_stop;
- s->slave.opaque = s;
+ s->irq = irq;
+ s->slave.event = s3c_i2c_event;
+ s->slave.send = s3c_i2c_tx;
+ s->slave.recv = s3c_i2c_rx;
+ s->bus = i2c_init_bus();
s3c_i2c_reset(s);
@@ -1687,19 +1720,20 @@
return s;
}
-struct i2c_master_s *s3c_i2c_master(struct s3c_i2c_state_s *s)
+i2c_bus *s3c_i2c_bus(struct s3c_i2c_state_s *s)
{
- return &s->master;
+ return s->bus;
}
/* Serial Peripheral Interface */
struct s3c_spi_state_s {
target_phys_addr_t base;
- void *pic;
- void *dma;
- struct s3c_gpio_state_s *gpio;
struct {
+ qemu_irq irq;
+ qemu_irq drq;
+ qemu_irq miso;
+
uint8_t control;
uint8_t pin;
uint8_t pre;
@@ -1719,23 +1753,17 @@
static void s3c_spi_update(struct s3c_spi_state_s *s)
{
- switch ((s->chan[0].control >> 5) & 3) { /* SMOD */
- case 1:
- pic_set_irq_new(s->pic, S3C_PIC_SPI0, 1);
- break;
- case 2:
- pic_set_irq_new(s->dma, S3C_RQ_SPI0, 1);
- break;
+ int i;
+ for (i = 0; i < 2; i ++) {
+ switch ((s->chan[i].control >> 5) & 3) { /* SMOD */
+ case 1:
+ qemu_irq_raise(s->chan[i].irq);
+ break;
+ case 2:
+ qemu_irq_raise(s->chan[i].drq);
+ break;
+ }
}
-
- switch ((s->chan[1].control >> 5) & 3) { /* SMOD */
- case 1:
- pic_set_irq_new(s->pic, S3C_PIC_SPI1, 1);
- break;
- case 2:
- pic_set_irq_new(s->dma, S3C_RQ_SPI1, 1);
- break;
- }
}
static void s3c_spi_reset(struct s3c_spi_state_s *s)
@@ -1851,17 +1879,10 @@
s3c_spi_write,
};
-static const struct {
- int cs, clk, miso, mosi;
-} s3c_spi_pins[2] = {
- { S3C_GPG(2), S3C_GPE(13), S3C_GPE(11), S3C_GPE(12) },
- { S3C_GPG(3), S3C_GPG(7), S3C_GPG(5), S3C_GPG(6) },
-};
-
-static void s3c_spi_bitbang_cs(int line, int level, void *opaque)
+static void s3c_spi_bitbang_cs(void *opaque, int line, int level)
{
struct s3c_spi_state_s *s = (struct s3c_spi_state_s *) opaque;
- int ch = (line == s3c_spi_pins[1].cs);
+ int ch = line;
if (s->chan[ch].cs_pin || level) {
if (s->chan[ch].bit && s->txrx[ch] && !s->btxrx[ch]) {
s->chan[ch].txbuf <<= 8 - s->chan[ch].bit;
@@ -1874,10 +1895,10 @@
s->chan[ch].cs_pin = !level;
}
-static void s3c_spi_bitbang_clk(int line, int level, void *opaque)
+static void s3c_spi_bitbang_clk(void *opaque, int line, int level)
{
struct s3c_spi_state_s *s = (struct s3c_spi_state_s *) opaque;
- int ch = (line == s3c_spi_pins[1].clk);
+ int ch = line;
if (!s->chan[ch].cs_pin)
goto done;
@@ -1886,7 +1907,7 @@
goto done;
if (s->btxrx[ch]) {
- s3c_gpio_set(s->gpio, s3c_spi_pins[ch].miso,
+ qemu_set_irq(s->chan[ch].miso,
s->btxrx[ch](s->opaque[ch], s->chan[ch].mosi_pin));
goto done;
}
@@ -1894,7 +1915,7 @@
s->chan[ch].txbuf <<= 1;
s->chan[ch].txbuf |= s->chan[ch].mosi_pin;
- s3c_gpio_set(s->gpio, s3c_spi_pins[ch].miso, (s->chan[ch].rxbuf >> 7) & 1);
+ qemu_set_irq(s->chan[ch].miso, (s->chan[ch].rxbuf >> 7) & 1);
s->chan[ch].rxbuf <<= 1;
if (++ s->chan[ch].bit == 8) {
@@ -1907,39 +1928,49 @@
s->chan[ch].clk_pin = level;
}
-static void s3c_spi_bitbang_mosi(int line, int level, void *opaque)
+static void s3c_spi_bitbang_mosi(void *opaque, int line, int level)
{
struct s3c_spi_state_s *s = (struct s3c_spi_state_s *) opaque;
- int ch = (line == s3c_spi_pins[1].mosi);
+ int ch = line;
s->chan[ch].mosi_pin = level;
}
+static const struct {
+ int cs, clk, miso, mosi;
+} s3c_spi_pins[2] = {
+ { S3C_GPG(2), S3C_GPE(13), S3C_GPE(11), S3C_GPE(12) },
+ { S3C_GPG(3), S3C_GPG(7), S3C_GPG(5), S3C_GPG(6) },
+};
+
static void s3c_spi_bitbang_init(struct s3c_spi_state_s *s,
struct s3c_gpio_state_s *gpio)
{
int i;
+ qemu_irq *cs = qemu_allocate_irqs(s3c_spi_bitbang_cs, s, 2);
+ qemu_irq *clk = qemu_allocate_irqs(s3c_spi_bitbang_clk, s, 2);
+ qemu_irq *mosi = qemu_allocate_irqs(s3c_spi_bitbang_mosi, s, 2);
+
for (i = 0; i < 2; i ++) {
- s3c_gpio_handler_set(gpio, s3c_spi_pins[i].cs,
- s3c_spi_bitbang_cs, s);
- s3c_gpio_handler_set(gpio, s3c_spi_pins[i].clk,
- s3c_spi_bitbang_clk, s);
- s3c_gpio_handler_set(gpio, s3c_spi_pins[i].mosi,
- s3c_spi_bitbang_mosi, s);
+ s3c_gpio_out_set(gpio, s3c_spi_pins[i].cs, cs[i]);
+ s3c_gpio_out_set(gpio, s3c_spi_pins[i].clk, clk[i]);
+ s->chan[i].miso = s3c_gpio_in_get(gpio)[s3c_spi_pins[i].miso];
+ s3c_gpio_out_set(gpio, s3c_spi_pins[i].mosi, mosi[i]);
}
-
- s->gpio = gpio;
}
struct s3c_spi_state_s *s3c_spi_init(target_phys_addr_t base,
- void *pic, void *dma, struct s3c_gpio_state_s *gpio)
+ qemu_irq irq0, qemu_irq drq0, qemu_irq irq1, qemu_irq drq1,
+ struct s3c_gpio_state_s *gpio)
{
int iomemtype;
struct s3c_spi_state_s *s = (struct s3c_spi_state_s *)
qemu_mallocz(sizeof(struct s3c_spi_state_s));
s->base = base;
- s->pic = pic;
- s->dma = dma;
+ s->chan[0].irq = irq0;
+ s->chan[0].drq = drq0;
+ s->chan[1].irq = irq1;
+ s->chan[1].drq = drq1;
s3c_spi_reset(s);
@@ -1980,11 +2011,11 @@
if (s->rx_en && s->rx_len)
s->control |= (1 << 6);
- pic_set_irq_new(s->dma, S3C_RQ_I2SSDO, (s->control >> 5) &
+ qemu_set_irq(s->dma[S3C_RQ_I2SSDO], (s->control >> 5) &
(s->control >> 7) & (s->fcontrol >> 15) & 1);
- pic_set_irq_new(s->dma, S3C_RQ_I2SSDI0, (s->control >> 4) &
+ qemu_set_irq(s->dma[S3C_RQ_I2SSDI0], (s->control >> 4) &
(s->control >> 6) & (s->fcontrol >> 14) & 1);
- pic_set_irq_new(s->dma, S3C_RQ_I2SSDI1, (s->control >> 4) &
+ qemu_set_irq(s->dma[S3C_RQ_I2SSDI1], (s->control >> 4) &
(s->control >> 6) & (s->fcontrol >> 14) & 1);
}
@@ -2098,7 +2129,7 @@
s3c_i2s_update(s);
}
-struct s3c_i2s_state_s *s3c_i2s_init(target_phys_addr_t base, void *dma)
+struct s3c_i2s_state_s *s3c_i2s_init(target_phys_addr_t base, qemu_irq *dma)
{
int iomemtype;
struct s3c_i2s_state_s *s = (struct s3c_i2s_state_s *)
@@ -2166,29 +2197,32 @@
}
/* Initialise an S3C2410A microprocessor. */
-struct s3c_state_s *s3c2410_init(DisplayState *ds)
+struct s3c_state_s *s3c2410_init(unsigned int sdram_size, DisplayState *ds)
{
struct s3c_state_s *s;
int iomemtype, i;
s = (struct s3c_state_s *) qemu_mallocz(sizeof(struct s3c_state_s));
- s->free_ram_start = 0;
s->env = cpu_init();
- cpu_arm_set_model(s->env, ARM_CPUID_ARM920T);
+ cpu_arm_set_model(s->env, "arm920t");
+ cpu_register_physical_memory(S3C_RAM_BASE, sdram_size,
+ qemu_ram_alloc(sdram_size) | IO_MEM_RAM);
+
/* If OM pins are 00, SRAM is mapped at 0x0 instead. */
cpu_register_physical_memory(S3C_SRAM_BASE, S3C_SRAM_SIZE,
- s->free_ram_start | IO_MEM_RAM);
- s->free_ram_start += S3C_SRAM_SIZE;
+ qemu_ram_alloc(S3C_SRAM_SIZE) | IO_MEM_RAM);
s->mc_base = 0x48000000;
s3c_mc_reset(s);
iomemtype = cpu_register_io_memory(0, s3c_mc_readfn, s3c_mc_writefn, s);
cpu_register_physical_memory(s->mc_base, 0xffffff, iomemtype);
- s->pic = s3c_pic_init(0x4a000000, s->env);
+ s->pic = s3c_pic_init(0x4a000000, arm_pic_init_cpu(s->env));
+ s->irq = s3c_pic_get(s->pic);
- s->dma = s3c_dma_init(0x4b000000, s->pic);
+ s->dma = s3c_dma_init(0x4b000000, &s->irq[S3C_PIC_DMA0]);
+ s->drq = s3c_dma_get(s->dma);
s->clkpwr_base = 0x4c000000;
s3c_clkpwr_reset(s);
@@ -2196,7 +2230,7 @@
s3c_clkpwr_writefn, s);
cpu_register_physical_memory(s->clkpwr_base, 0xffffff, iomemtype);
- s->lcd = s3c_lcd_init(0x4d000000, ds, s->pic);
+ s->lcd = s3c_lcd_init(0x4d000000, ds, s->irq[S3C_PIC_LCD]);
s->nand_base = 0x4e000000;
s3c_nand_reset(s);
@@ -2205,34 +2239,38 @@
cpu_register_physical_memory(s->nand_base, 0xffffff, iomemtype);
for (i = 0; s3c2410_uart[i].base; i ++) {
- s->uart[i] = s3c_uart_init(s3c2410_uart[i].base, s->pic, s->dma,
- s3c2410_uart[i].irq, s3c2410_uart[i].dma);
+ s->uart[i] = s3c_uart_init(s3c2410_uart[i].base,
+ &s->irq[s3c2410_uart[i].irq[0]],
+ &s->drq[s3c2410_uart[i].dma[0]]);
if (serial_hds[i])
s3c_uart_attach(s->uart[i], serial_hds[i]);
}
- s->timers = s3c_timers_init(0x51000000, s->pic, s->dma);
+ s->timers = s3c_timers_init(0x51000000, &s->irq[S3C_PIC_TIMER0], s->drq);
- s->udc = s3c_udc_init(0x52000000, s->pic, s->dma);
+ s->udc = s3c_udc_init(0x52000000, s->irq[S3C_PIC_USBD], s->drq);
/* Watchdog at 0x53000000 */
- s->i2c = s3c_i2c_init(0x54000000, s->pic);
+ s->i2c = s3c_i2c_init(0x54000000, s->irq[S3C_PIC_IIC]);
- s->i2s = s3c_i2s_init(0x55000000, s->dma);
+ s->i2s = s3c_i2s_init(0x55000000, s->drq);
- s->io = s3c_gpio_init(0x56000000, s->pic);
+ s->io = s3c_gpio_init(0x56000000, s->irq);
- s->rtc = s3c_rtc_init(0x57000000, s->pic);
+ s->rtc = s3c_rtc_init(0x57000000, s->irq[S3C_PIC_RTC]);
- s->adc = s3c_adc_init(0x58000000, s->pic);
+ s->adc = s3c_adc_init(0x58000000, s->irq[S3C_PICS_ADC],
+ s->irq[S3C_PICS_TC]);
- s->spi = s3c_spi_init(0x59000000, s->pic, s->dma, s->io);
+ s->spi = s3c_spi_init(0x59000000,
+ s->irq[S3C_PIC_SPI0], s->drq[S3C_RQ_SPI0],
+ s->irq[S3C_PIC_SPI1], s->drq[S3C_RQ_SPI1], s->io);
- s->mmci = s3c_mmci_init(0x5a000000, s->pic, s->dma);
+ s->mmci = s3c_mmci_init(0x5a000000, s->irq[S3C_PIC_SDI], s->drq);
if (usb_enabled) {
- usb_ohci_init_memio(0x49000000, 3, -1, s->pic, S3C_PIC_USBH);
+ usb_ohci_init_memio(0x49000000, 3, -1, s->irq[S3C_PIC_USBH]);
}
/* Power on reset */
Modified: trunk/src/host/qemu-neo1973/hw/s3c24xx_gpio.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/s3c24xx_gpio.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/s3c24xx_gpio.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -10,10 +10,10 @@
#define S3C_IO_BANKS 8
-struct s3c_gpio_state_s {
- s3c_pic_handler_t handler; /* Modelled as an interrupt controller */
+struct s3c_gpio_state_s { /* Modelled as an interrupt controller */
target_phys_addr_t base;
- void *pic;
+ qemu_irq *pic;
+ qemu_irq *in;
struct {
int n;
@@ -21,10 +21,7 @@
uint32_t dat;
uint32_t up;
uint32_t mask;
- struct {
- gpio_handler_t fn;
- void *opaque;
- } handler[32];
+ qemu_irq handler[32];
} bank[S3C_IO_BANKS];
uint32_t inform[2];
@@ -44,18 +41,18 @@
s->eintpend |= (1 << irq) & 0x00fffff0;
switch (irq) {
case 0 ... 3:
- pic_set_irq_new(s->pic, S3C_PIC_EINT0 + irq, 1);
+ qemu_irq_raise(s->pic[S3C_PIC_EINT0 + irq]);
break;
case 4 ... 7:
- pic_set_irq_new(s->pic, S3C_PIC_EINT4, 1);
+ qemu_irq_raise(s->pic[S3C_PIC_EINT4]);
break;
case 8 ... 23:
- pic_set_irq_new(s->pic, S3C_PIC_EINT8, 1);
+ qemu_irq_raise(s->pic[S3C_PIC_EINT8]);
break;
}
}
-void s3c_gpio_set(void *opaque, int line, int level)
+static void s3c_gpio_set(void *opaque, int line, int level)
{
struct s3c_gpio_state_s *s = (struct s3c_gpio_state_s *) opaque;
int e, eint, bank = line >> 5;
@@ -106,15 +103,18 @@
}
}
-void s3c_gpio_handler_set(struct s3c_gpio_state_s *s, int line,
- gpio_handler_t handler, void *opaque)
+qemu_irq *s3c_gpio_in_get(struct s3c_gpio_state_s *s)
{
+ return s->in;
+}
+
+void s3c_gpio_out_set(struct s3c_gpio_state_s *s, int line, qemu_irq handler)
+{
int bank = line >> 5;
line &= 0x1f;
if (bank >= S3C_IO_BANKS || line >= s->bank[bank].n)
cpu_abort(cpu_single_env, "%s: No I/O port %i\n", __FUNCTION__, line);
- s->bank[bank].handler[line].fn = handler;
- s->bank[bank].handler[line].opaque = opaque;
+ s->bank[bank].handler[line] = handler;
}
void s3c_gpio_reset(struct s3c_gpio_state_s *s)
@@ -281,17 +281,11 @@
s->bank[bank].dat = value;
while ((ln = ffs(diff))) {
ln --;
- if (s->bank[bank].handler[ln].fn) {
+ if (s->bank[bank].handler[ln]) {
if (bank && ((s->bank[bank].con >> (2 * ln)) & 3) == 1)
- s->bank[bank].handler[ln].fn(
- (bank << 5) | ln,
- (value >> ln) & 1,
- s->bank[bank].handler[ln].opaque);
+ qemu_set_irq(s->bank[bank].handler[ln], (value >> ln) & 1);
else if (!bank && ((s->bank[bank].con >> ln) & 1) == 0)
- s->bank[bank].handler[ln].fn(
- (bank << 5) | ln,
- (value >> ln) & 1,
- s->bank[bank].handler[ln].opaque);
+ qemu_set_irq(s->bank[bank].handler[ln], (value >> ln) & 1);
}
diff &= ~(1 << ln);
}
@@ -316,7 +310,7 @@
s3c_gpio_write,
};
-struct s3c_gpio_state_s *s3c_gpio_init(target_phys_addr_t base, void *pic)
+struct s3c_gpio_state_s *s3c_gpio_init(target_phys_addr_t base, qemu_irq *pic)
{
int iomemtype;
struct s3c_gpio_state_s *s = (struct s3c_gpio_state_s *)
@@ -324,7 +318,7 @@
s->base = base;
s->pic = pic;
- s->handler = s3c_gpio_set;
+ s->in = qemu_allocate_irqs(s3c_gpio_set, s, S3C_GP_MAX);
s->bank[0].n = 23;
s->bank[1].n = 11;
Modified: trunk/src/host/qemu-neo1973/hw/s3c24xx_lcd.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/s3c24xx_lcd.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/s3c24xx_lcd.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -12,7 +12,7 @@
struct s3c_lcd_state_s {
target_phys_addr_t base;
- void *pic;
+ void *irq;
DisplayState *ds;
s3c_drawfn_t *line_fn;
@@ -48,7 +48,7 @@
static void s3c_lcd_update(struct s3c_lcd_state_s *s)
{
s->intpnd |= s->srcpnd & ~s->intmsk;
- pic_set_irq_new(s->pic, S3C_PIC_LCD, !!s->intpnd);
+ qemu_set_irq(s->irq, !!s->intpnd);
}
void s3c_lcd_reset(struct s3c_lcd_state_s *s)
@@ -184,7 +184,7 @@
break;
case S3C_LCDSADDR1:
s->saddr[0] = value;
- s->fb = phys_ram_base + S3C_SRAM_SIZE +
+ s->fb = phys_ram_base +
(((s->saddr[0] << 1) & 0x7ffffffe) - S3C_RAM_BASE);
s->invalidate = 1;
break;
@@ -428,10 +428,8 @@
}
if (dirty[0] || s->invalidate) {
s->fn(s->palette, dest, src, s->width, s->dest_width);
- if (y > maxy) {
- maxy = y;
- end = new_addr;
- }
+ maxy = y;
+ end = new_addr;
if (y < miny) {
miny = y;
start = addr;
@@ -474,14 +472,14 @@
#include "s3c24xx_template.h"
struct s3c_lcd_state_s *s3c_lcd_init(target_phys_addr_t base, DisplayState *ds,
- void *pic)
+ qemu_irq irq)
{
int iomemtype;
struct s3c_lcd_state_s *s = (struct s3c_lcd_state_s *)
qemu_mallocz(sizeof(struct s3c_lcd_state_s));
s->base = base;
- s->pic = pic;
+ s->irq = irq;
s->ds = ds;
s3c_lcd_reset(s);
Modified: trunk/src/host/qemu-neo1973/hw/s3c24xx_mmci.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/s3c24xx_mmci.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/s3c24xx_mmci.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -11,10 +11,10 @@
struct s3c_mmci_state_s {
target_phys_addr_t base;
- void *pic;
- void *dma;
+ qemu_irq irq;
+ qemu_irq *dma;
- struct sd_state_s *card;
+ SDState *card;
int blklen;
int blknum;
@@ -72,25 +72,25 @@
s->dstatus |= 1 << 0; /* RxDatOn */
while (s->fifolen < 64 && s->blklen_cnt) {
s->fifo[(s->fifostart + s->fifolen ++) & 63] =
- sd_read_datline(s->card);
+ sd_read_data(s->card);
if (!(-- s->blklen_cnt))
if (-- s->blknum_cnt)
s->blklen_cnt = s->blklen;
}
if ((s->mask & (1 << 0)) && /* RFHalf */
s->fifolen > 31 && len < 32)
- pic_set_irq_new(s->pic, S3C_PIC_SDI, 1);
+ qemu_irq_raise(s->irq);
if ((s->mask & (1 << 1)) && /* RFFull */
s->fifolen > 63 && len < 64)
- pic_set_irq_new(s->pic, S3C_PIC_SDI, 1);
+ qemu_irq_raise(s->irq);
if ((s->mask & (1 << 2)) && !s->blklen_cnt) /* RFLast */
- pic_set_irq_new(s->pic, S3C_PIC_SDI, 1);
+ qemu_irq_raise(s->irq);
dmalevel = !!s->fifolen;
} else if (((s->dcontrol >> 12) & 3) == 3) { /* DatMode */
s->dstatus &= ~3;
s->dstatus |= 1 << 0; /* TxDatOn */
while (s->fifolen && s->blklen_cnt) {
- sd_write_datline(s->card, s->fifo[s->fifostart ++]);
+ sd_write_data(s->card, s->fifo[s->fifostart ++]);
s->fifostart &= 63;
s->fifolen --;
if (!(-- s->blklen_cnt))
@@ -98,10 +98,10 @@
s->blklen_cnt = s->blklen;
}
if ((s->mask & (1 << 3)) && !s->fifolen && len) /* TFEmpty */
- pic_set_irq_new(s->pic, S3C_PIC_SDI, 1);
+ qemu_irq_raise(s->irq);
if ((s->mask & (1 << 4)) && /* TFHalf */
s->fifolen < 33 && len > 32)
- pic_set_irq_new(s->pic, S3C_PIC_SDI, 1);
+ qemu_irq_raise(s->irq);
dmalevel = (s->fifolen < 64) && (s->blklen_cnt > 0);
} else
return;
@@ -111,31 +111,31 @@
s->dstatus &= ~3;
s->dstatus |= 1 << 4; /* DatFin */
if (s->mask & (1 << 7)) /* DatFin */
- pic_set_irq_new(s->pic, S3C_PIC_SDI, 1);
+ qemu_irq_raise(s->irq);
}
dmaupdate:
if (s->dcontrol & (1 << 15)) { /* EnDMA */
- pic_set_irq_new(s->dma, S3C_RQ_SDI0, dmalevel);
- pic_set_irq_new(s->dma, S3C_RQ_SDI1, dmalevel);
- pic_set_irq_new(s->dma, S3C_RQ_SDI2, dmalevel);
+ qemu_set_irq(s->dma[S3C_RQ_SDI0], dmalevel);
+ qemu_set_irq(s->dma[S3C_RQ_SDI1], dmalevel);
+ qemu_set_irq(s->dma[S3C_RQ_SDI2], dmalevel);
}
}
static void s3c_mmci_cmd_submit(struct s3c_mmci_state_s *s)
{
- int rsplen;
+ int rsplen, i;
struct sd_request_s request;
- union sd_response_u response;
+ char response[16];
request.cmd = s->ccontrol & 0x3f;
request.arg = s->arg;
request.crc = 0; /* FIXME */
- response = sd_write_cmdline(s->card, request, &rsplen);
+ rsplen = sd_do_command(s->card, &request, response);
s->cstatus = (s->cstatus & ~0x11ff) | request.cmd; /* RspIndex */
s->cstatus |= 1 << 11; /* CmdSent */
if (s->mask & (1 << 16)) /* CmdSent */
- pic_set_irq_new(s->pic, S3C_PIC_SDI, 1);
+ qemu_irq_raise(s->irq);
memset(s->resp, 0, sizeof(s->resp));
if (!(s->ccontrol & (1 << 9))) /* WaitRsp */
@@ -143,42 +143,20 @@
if (s->ccontrol & (1 << 10)) { /* LongRsp */
/* R2 */
- if (rsplen < 128)
+ if (rsplen < 16)
goto timeout;
-
- s->resp[0] = bswap16(response.r2.reg[1]) |
- (bswap16(response.r2.reg[0]) << 16);
- s->resp[1] = bswap16(response.r2.reg[3]) |
- (bswap16(response.r2.reg[2]) << 16);
- s->resp[2] = bswap16(response.r2.reg[5]) |
- (bswap16(response.r2.reg[4]) << 16);
- s->resp[3] = bswap16(response.r2.reg[7]) |
- (bswap16(response.r2.reg[6]) << 16);
} else {
/* R1, R3, R4, R5 or R6 */
- if (request.cmd == 3) { /* R6 */
- if (rsplen < 48)
- goto timeout;
-
- s->resp[0] = response.r6.status | (response.r6.arg << 16);
- s->resp[1] = response.r6.crc << 24;
- } else if (request.cmd == 41) { /* R3 */
- if (rsplen < 32)
- goto timeout;
-
- s->resp[0] = response.r3.ocr_reg;
- } else {
- if (rsplen < 48)
- goto timeout;
-
- s->resp[0] = response.r1.status;
- s->resp[1] = response.r1.crc << 24;
- }
+ if (rsplen < 4)
+ goto timeout;
}
+ for (i = 0; i < rsplen; i ++)
+ s->resp[i >> 2] |= response[i] << ((i & 3) << 3);
+
s->cstatus |= 1 << 9; /* RspFin */
if (s->mask & (1 << 14)) /* RspEnd */
- pic_set_irq_new(s->pic, S3C_PIC_SDI, 1);
+ qemu_irq_raise(s->irq);
complete:
s->blklen_cnt = s->blklen;
@@ -198,7 +176,7 @@
timeout:
s->cstatus |= 1 << 10; /* CmdTout */
if (s->mask & (1 << 15)) /* CmdTout */
- pic_set_irq_new(s->pic, S3C_PIC_SDI, 1);
+ qemu_irq_raise(s->irq);
}
#define S3C_SDICON 0x00 /* SDI Control register */
@@ -378,14 +356,14 @@
};
struct s3c_mmci_state_s *s3c_mmci_init(target_phys_addr_t base,
- void *pic, void *dma)
+ qemu_irq irq, qemu_irq *dma)
{
int iomemtype;
struct s3c_mmci_state_s *s = (struct s3c_mmci_state_s *)
qemu_mallocz(sizeof(struct s3c_mmci_state_s));
s->base = base;
- s->pic = pic;
+ s->irq = irq;
s->dma = dma;
s3c_mmci_reset(s);
@@ -395,7 +373,7 @@
cpu_register_physical_memory(s->base, 0xffffff, iomemtype);
/* Instantiate the actual storage */
- s->card = sd_init();
+ s->card = sd_init(sd_bdrv);
return s;
}
Modified: trunk/src/host/qemu-neo1973/hw/s3c24xx_rtc.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/s3c24xx_rtc.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/s3c24xx_rtc.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -10,7 +10,7 @@
struct s3c_rtc_state_s {
target_phys_addr_t base;
- void *pic;
+ qemu_irq irq;
int enable;
QEMUTimer *timer;
QEMUTimer *hz;
@@ -60,7 +60,7 @@
struct s3c_rtc_state_s *s = (struct s3c_rtc_state_s *) opaque;
if (!(s->tick & (1 << 7)))
return;
- pic_set_irq_new(s->pic, S3C_PIC_RTC, 1);
+ qemu_irq_raise(s->irq);
s3c_rtc_tick_mod(s);
}
@@ -268,14 +268,14 @@
s3c_rtc_write,
};
-struct s3c_rtc_state_s *s3c_rtc_init(target_phys_addr_t base, void *pic)
+struct s3c_rtc_state_s *s3c_rtc_init(target_phys_addr_t base, qemu_irq irq)
{
int iomemtype;
struct s3c_rtc_state_s *s = (struct s3c_rtc_state_s *)
qemu_mallocz(sizeof(struct s3c_rtc_state_s));
s->base = base;
- s->pic = pic;
+ s->irq = irq;
s->timer = qemu_new_timer(vm_clock, s3c_rtc_tick, s);
s->hz = qemu_new_timer(rt_clock, s3c_rtc_hz, s);
Modified: trunk/src/host/qemu-neo1973/hw/s3c24xx_udc.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/s3c24xx_udc.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/s3c24xx_udc.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -13,8 +13,8 @@
struct s3c_udc_state_s {
target_phys_addr_t base;
USBDevice dev;
- void *pic;
- void *dma;
+ qemu_irq irq;
+ qemu_irq *dma;
/* Use FIFOs big enough to hold entire packets, just don't report
* lengths greater than 16 and 64 bytes for EP0 and EP1-4 respectively. */
@@ -90,7 +90,7 @@
s->ep_intr |= 1 << ep;
s->ep_intr &= s->ep_mask;
s->usb_intr &= s->usb_mask;
- pic_set_irq_new(s->pic, S3C_PIC_USBD, s->ep_intr | s->usb_intr);
+ qemu_set_irq(s->irq, s->ep_intr | s->usb_intr);
}
static void s3c_udc_queue_packet(uint8_t *dst, uint8_t *src,
@@ -669,14 +669,14 @@
}
struct s3c_udc_state_s *s3c_udc_init(target_phys_addr_t base,
- void *pic, void *dma)
+ qemu_irq irq, qemu_irq *dma)
{
int iomemtype;
struct s3c_udc_state_s *s = (struct s3c_udc_state_s *)
qemu_mallocz(sizeof(struct s3c_udc_state_s));
s->base = base;
- s->pic = pic;
+ s->irq = irq;
s->dma = dma;
s->dev.speed = USB_SPEED_FULL;
Modified: trunk/src/host/qemu-neo1973/hw/sb16.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/sb16.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/sb16.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -54,6 +54,7 @@
typedef struct SB16State {
QEMUSoundCard card;
+ qemu_irq *pic;
int irq;
int dma;
int hdma;
@@ -187,7 +188,7 @@
{
SB16State *s = opaque;
s->can_write = 1;
- pic_set_irq (s->irq, 1);
+ qemu_irq_raise (s->pic[s->irq]);
}
#define DMA8_AUTO 1
@@ -595,7 +596,7 @@
case 0xf3:
dsp_out_data (s, 0xaa);
s->mixer_regs[0x82] |= (cmd == 0xf2) ? 1 : 2;
- pic_set_irq (s->irq, 1);
+ qemu_irq_raise (s->pic[s->irq]);
break;
case 0xf9:
@@ -763,7 +764,7 @@
bytes = samples << s->fmt_stereo << (s->fmt_bits == 16);
ticks = (bytes * ticks_per_sec) / freq;
if (ticks < ticks_per_sec / 1024) {
- pic_set_irq (s->irq, 1);
+ qemu_irq_raise (s->pic[s->irq]);
}
else {
if (s->aux_ts) {
@@ -855,10 +856,10 @@
static void reset (SB16State *s)
{
- pic_set_irq (s->irq, 0);
+ qemu_irq_lower (s->pic[s->irq]);
if (s->dma_auto) {
- pic_set_irq (s->irq, 1);
- pic_set_irq (s->irq, 0);
+ qemu_irq_raise (s->pic[s->irq]);
+ qemu_irq_lower (s->pic[s->irq]);
}
s->mixer_regs[0x82] = 0;
@@ -894,7 +895,7 @@
if (s->v2x6 == 1) {
if (0 && s->highspeed) {
s->highspeed = 0;
- pic_set_irq (s->irq, 0);
+ qemu_irq_lower (s->pic[s->irq]);
control (s, 0);
}
else {
@@ -1005,7 +1006,7 @@
if (s->mixer_regs[0x82] & 1) {
ack = 1;
s->mixer_regs[0x82] &= 1;
- pic_set_irq (s->irq, 0);
+ qemu_irq_lower (s->pic[s->irq]);
}
break;
@@ -1014,7 +1015,7 @@
if (s->mixer_regs[0x82] & 2) {
ack = 1;
s->mixer_regs[0x82] &= 2;
- pic_set_irq (s->irq, 0);
+ qemu_irq_lower (s->pic[s->irq]);
}
break;
@@ -1222,7 +1223,7 @@
if (s->left_till_irq <= 0) {
s->mixer_regs[0x82] |= (nchan & 4) ? 2 : 1;
- pic_set_irq (s->irq, 1);
+ qemu_irq_raise (s->pic[s->irq]);
if (0 == s->dma_auto) {
control (s, 0);
speaker (s, 0);
@@ -1389,7 +1390,7 @@
return 0;
}
-int SB16_init (AudioState *audio)
+int SB16_init (AudioState *audio, qemu_irq *pic)
{
SB16State *s;
int i;
@@ -1409,6 +1410,7 @@
}
s->cmd = -1;
+ s->pic = pic;
s->irq = conf.irq;
s->dma = conf.dma;
s->hdma = conf.hdma;
Modified: trunk/src/host/qemu-neo1973/hw/scsi-disk.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/scsi-disk.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/scsi-disk.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -345,7 +345,7 @@
DPRINTF("Request Sense (len %d)\n", len);
if (len < 4)
goto fail;
- memset(buf, 0, 4);
+ memset(outbuf, 0, 4);
outbuf[0] = 0xf0;
outbuf[1] = 0;
outbuf[2] = s->sense;
@@ -371,7 +371,7 @@
Some later commands are also implemented. */
outbuf[2] = 3;
outbuf[3] = 2; /* Format 2 */
- outbuf[4] = 32;
+ outbuf[4] = 31;
/* Sync data transfer and TCQ. */
outbuf[7] = 0x10 | (s->tcq ? 0x02 : 0);
r->buf_len = 36;
@@ -404,10 +404,11 @@
p += 4;
if ((page == 8 || page == 0x3f)) {
/* Caching page. */
+ memset(p,0,20);
p[0] = 8;
p[1] = 0x12;
p[2] = 4; /* WCE */
- p += 19;
+ p += 20;
}
if ((page == 0x3f || page == 0x2a)
&& (bdrv_get_type_hint(s->bdrv) == BDRV_TYPE_CDROM)) {
@@ -437,7 +438,7 @@
p[19] = (16 * 176) & 0xff;
p[20] = (16 * 176) >> 8; // 16x write speed current
p[21] = (16 * 176) & 0xff;
- p += 21;
+ p += 22;
}
r->buf_len = p - outbuf;
outbuf[0] = r->buf_len - 4;
Modified: trunk/src/host/qemu-neo1973/hw/sd.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/sd.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/sd.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -3,6 +3,7 @@
* layer specification, Version 1.10."
*
* Copyright (c) 2006 Andrzej Zaborowski <balrog at zabor.org>
+ * Copyright (c) 2007 CodeSourcery
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -30,173 +31,175 @@
#include "sd.h"
-struct sd_state_s {
- enum {
- sd_inactive,
- sd_card_identification_mode,
- sd_data_transfer_mode,
- } mode;
- enum {
- sd_inactive_state = -1,
- sd_idle_state = 0,
- sd_ready_state,
- sd_identification_state,
- sd_standby_state,
- sd_transfer_state,
- sd_sendingdata_state,
- sd_receivingdata_state,
- sd_programming_state,
- sd_disconnect_state,
- } state;
- uint32_t ocr;
- uint8_t scr[8];
- uint8_t cid[16];
- uint8_t csd[16];
- uint16_t rca;
- uint32_t card_status;
- uint8_t sd_status[64];
- int wp_switch;
- int *wp_groups;
- uint32_t size;
- int blk_len;
- uint32_t erase_start;
- uint32_t erase_end;
- uint8_t pwd[16];
- int pwd_len;
- int function_group[6];
+//#define DEBUG_SD 1
- int current_cmd;
- int blk_written;
- uint32_t data_start;
- uint32_t data_offset;
- uint8_t data[512];
- void (*readonly_cb)(void *, int);
- void (*inserted_cb)(void *, int);
- void *opaque;
- BlockDriverState *bdrv;
+#ifdef DEBUG_SD
+#define DPRINTF(fmt, args...) \
+do { printf("SD: " fmt , ##args); } while (0)
+#else
+#define DPRINTF(fmt, args...) do {} while(0)
+#endif
+
+typedef enum {
+ sd_r0 = 0, /* no response */
+ sd_r1, /* normal response command */
+ sd_r2_i, /* CID register */
+ sd_r2_s, /* CSD register */
+ sd_r3, /* OCR register */
+ sd_r6 = 6, /* Published RCA response */
+ sd_r1b = -1,
+} sd_rsp_type_t;
+
+struct SDState {
+ enum {
+ sd_inactive,
+ sd_card_identification_mode,
+ sd_data_transfer_mode,
+ } mode;
+ enum {
+ sd_inactive_state = -1,
+ sd_idle_state = 0,
+ sd_ready_state,
+ sd_identification_state,
+ sd_standby_state,
+ sd_transfer_state,
+ sd_sendingdata_state,
+ sd_receivingdata_state,
+ sd_programming_state,
+ sd_disconnect_state,
+ } state;
+ uint32_t ocr;
+ uint8_t scr[8];
+ uint8_t cid[16];
+ uint8_t csd[16];
+ uint16_t rca;
+ uint32_t card_status;
+ uint8_t sd_status[64];
+ int wp_switch;
+ int *wp_groups;
+ uint32_t size;
+ int blk_len;
+ uint32_t erase_start;
+ uint32_t erase_end;
+ uint8_t pwd[16];
+ int pwd_len;
+ int function_group[6];
+
+ int current_cmd;
+ int blk_written;
+ uint32_t data_start;
+ uint32_t data_offset;
+ uint8_t data[512];
+ void (*readonly_cb)(void *, int);
+ void (*inserted_cb)(void *, int);
+ void *opaque;
+ BlockDriverState *bdrv;
};
-static void sd_set_status(struct sd_state_s *sd) {
- switch (sd->state) {
- case sd_inactive_state:
- sd->mode = sd_inactive;
- break;
+static void sd_set_status(SDState *sd)
+{
+ switch (sd->state) {
+ case sd_inactive_state:
+ sd->mode = sd_inactive;
+ break;
- case sd_idle_state:
- case sd_ready_state:
- case sd_identification_state:
- sd->mode = sd_card_identification_mode;
- break;
+ case sd_idle_state:
+ case sd_ready_state:
+ case sd_identification_state:
+ sd->mode = sd_card_identification_mode;
+ break;
- case sd_standby_state:
- case sd_transfer_state:
- case sd_sendingdata_state:
- case sd_receivingdata_state:
- case sd_programming_state:
- case sd_disconnect_state:
- sd->mode = sd_data_transfer_mode;
- break;
- }
+ case sd_standby_state:
+ case sd_transfer_state:
+ case sd_sendingdata_state:
+ case sd_receivingdata_state:
+ case sd_programming_state:
+ case sd_disconnect_state:
+ sd->mode = sd_data_transfer_mode;
+ break;
+ }
- sd->card_status &= ~CURRENT_STATE;
- sd->card_status |= sd->state << 9;
+ sd->card_status &= ~CURRENT_STATE;
+ sd->card_status |= sd->state << 9;
}
const sd_cmd_type_t sd_cmd_type[64] = {
- sd_bc, sd_none, sd_bcr, sd_bcr, sd_none, sd_none, sd_none, sd_ac,
- sd_none, sd_ac, sd_ac, sd_adtc, sd_ac, sd_ac, sd_none, sd_ac,
- sd_ac, sd_adtc, sd_adtc, sd_none, sd_none, sd_none, sd_none, sd_none,
- sd_adtc, sd_adtc, sd_adtc, sd_adtc, sd_ac, sd_ac, sd_adtc, sd_none,
- sd_ac, sd_ac, sd_none, sd_none, sd_none, sd_none, sd_ac, sd_none,
- sd_none, sd_none, sd_bc, sd_none, sd_none, sd_none, sd_none, sd_none,
- sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_ac,
- sd_adtc, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none,
+ sd_bc, sd_none, sd_bcr, sd_bcr, sd_none, sd_none, sd_none, sd_ac,
+ sd_none, sd_ac, sd_ac, sd_adtc, sd_ac, sd_ac, sd_none, sd_ac,
+ sd_ac, sd_adtc, sd_adtc, sd_none, sd_none, sd_none, sd_none, sd_none,
+ sd_adtc, sd_adtc, sd_adtc, sd_adtc, sd_ac, sd_ac, sd_adtc, sd_none,
+ sd_ac, sd_ac, sd_none, sd_none, sd_none, sd_none, sd_ac, sd_none,
+ sd_none, sd_none, sd_bc, sd_none, sd_none, sd_none, sd_none, sd_none,
+ sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_ac,
+ sd_adtc, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none,
};
const sd_cmd_type_t sd_acmd_type[64] = {
- sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_ac, sd_none,
- sd_none, sd_none, sd_none, sd_none, sd_none, sd_adtc, sd_none, sd_none,
- sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_adtc, sd_ac,
- sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none,
- sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none,
- sd_none, sd_bcr, sd_ac, sd_none, sd_none, sd_none, sd_none, sd_none,
- sd_none, sd_none, sd_none, sd_adtc, sd_none, sd_none, sd_none, sd_none,
- sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none,
+ sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_ac, sd_none,
+ sd_none, sd_none, sd_none, sd_none, sd_none, sd_adtc, sd_none, sd_none,
+ sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_adtc, sd_ac,
+ sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none,
+ sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none,
+ sd_none, sd_bcr, sd_ac, sd_none, sd_none, sd_none, sd_none, sd_none,
+ sd_none, sd_none, sd_none, sd_adtc, sd_none, sd_none, sd_none, sd_none,
+ sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none, sd_none,
};
static const int sd_cmd_class[64] = {
- 0, 0, 0, 0, 0, 9, 10, 0, 0, 0, 0, 1, 0, 0, 0, 0,
- 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 6, 6, 6, 6,
- 5, 5, 10, 10, 10, 10, 5, 9, 9, 9, 7, 7, 7, 7, 7, 7,
- 7, 7, 10, 7, 9, 9, 9, 8, 8, 10, 8, 8, 8, 8, 8, 8,
+ 0, 0, 0, 0, 0, 9, 10, 0, 0, 0, 0, 1, 0, 0, 0, 0,
+ 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 6, 6, 6, 6,
+ 5, 5, 10, 10, 10, 10, 5, 9, 9, 9, 7, 7, 7, 7, 7, 7,
+ 7, 7, 10, 7, 9, 9, 9, 8, 8, 10, 8, 8, 8, 8, 8, 8,
};
-static const sd_rsp_type_t sd_cmd_response[64] = {
- sd_nore, sd_nore, sd_r2, sd_r6, sd_nore, sd_nore, sd_r1, sd_r1b,
- sd_nore, sd_r2, sd_r2, sd_nore, sd_r1b, sd_r1, sd_nore, sd_nore,
- sd_r1, sd_r1, sd_r1, sd_nore, sd_nore, sd_nore, sd_nore, sd_nore,
- sd_r1, sd_r1, sd_r1, sd_r1, sd_r1b, sd_r1b, sd_r1, sd_nore,
- sd_r1, sd_r1, sd_nore, sd_nore, sd_nore, sd_nore, sd_r1b, sd_nore,
- sd_nore, sd_nore, sd_r1, sd_nore, sd_nore, sd_nore, sd_nore, sd_nore,
- sd_nore, sd_nore, sd_nore, sd_nore, sd_nore, sd_nore, sd_nore, sd_r1,
- sd_r1, sd_nore, sd_nore, sd_nore, sd_nore, sd_nore, sd_nore, sd_nore,
-};
+static uint8_t sd_crc7(void *message, size_t width)
+{
+ int i, bit;
+ uint8_t shift_reg = 0x00;
+ uint8_t *msg = (uint8_t *) message;
-static const sd_rsp_type_t sd_acmd_response[64] = {
- sd_nore, sd_nore, sd_nore, sd_nore, sd_nore, sd_nore, sd_r1, sd_nore,
- sd_nore, sd_nore, sd_nore, sd_nore, sd_nore, sd_r1, sd_nore, sd_nore,
- sd_nore, sd_nore, sd_nore, sd_nore, sd_nore, sd_nore, sd_r1, sd_nore,
- sd_nore, sd_nore, sd_nore, sd_nore, sd_nore, sd_nore, sd_nore, sd_nore,
- sd_nore, sd_nore, sd_nore, sd_nore, sd_nore, sd_nore, sd_nore, sd_nore,
- sd_nore, sd_r3, sd_r1, sd_nore, sd_nore, sd_nore, sd_nore, sd_nore,
- sd_nore, sd_nore, sd_nore, sd_r1, sd_nore, sd_nore, sd_nore, sd_nore,
- sd_nore, sd_nore, sd_nore, sd_nore, sd_nore, sd_nore, sd_nore, sd_nore,
-};
+ for (i = 0; i < width; i ++, msg ++)
+ for (bit = 7; bit >= 0; bit --) {
+ shift_reg <<= 1;
+ if ((shift_reg >> 7) ^ ((*msg >> bit) & 1))
+ shift_reg ^= 0x89;
+ }
-static uint8_t sd_crc7(void *message, size_t width) {
- int i, bit;
- uint8_t shift_reg = 0x00;
- uint8_t *msg = (uint8_t *) message;
-
- for (i = 0; i < width; i ++, msg ++)
- for (bit = 7; bit >= 0; bit --) {
- shift_reg <<= 1;
- if ((shift_reg >> 7) ^ ((*msg >> bit) & 1))
- shift_reg ^= 0x89;
- }
-
- return shift_reg;
+ return shift_reg;
}
-static uint16_t sd_crc16(void *message, size_t width) {
- int i, bit;
- uint16_t shift_reg = 0x0000;
- uint16_t *msg = (uint16_t *) message;
- width <<= 1;
+static uint16_t sd_crc16(void *message, size_t width)
+{
+ int i, bit;
+ uint16_t shift_reg = 0x0000;
+ uint16_t *msg = (uint16_t *) message;
+ width <<= 1;
- for (i = 0; i < width; i ++, msg ++)
- for (bit = 15; bit >= 0; bit --) {
- shift_reg <<= 1;
- if ((shift_reg >> 15) ^ ((*msg >> bit) & 1))
- shift_reg ^= 0x1011;
- }
+ for (i = 0; i < width; i ++, msg ++)
+ for (bit = 15; bit >= 0; bit --) {
+ shift_reg <<= 1;
+ if ((shift_reg >> 15) ^ ((*msg >> bit) & 1))
+ shift_reg ^= 0x1011;
+ }
- return shift_reg;
+ return shift_reg;
}
-static void sd_set_ocr(struct sd_state_s *sd) {
- sd->ocr = 0x80fffff0;
+static void sd_set_ocr(SDState *sd)
+{
+ sd->ocr = 0x80fffff0;
}
-static void sd_set_scr(struct sd_state_s *sd) {
- sd->scr[0] = 0x00; /* SCR Structure */
- sd->scr[1] = 0x2f; /* SD Security Support */
- sd->scr[2] = 0x00;
- sd->scr[3] = 0x00;
- sd->scr[4] = 0x00;
- sd->scr[5] = 0x00;
- sd->scr[6] = 0x00;
- sd->scr[7] = 0x00;
+static void sd_set_scr(SDState *sd)
+{
+ sd->scr[0] = 0x00; /* SCR Structure */
+ sd->scr[1] = 0x2f; /* SD Security Support */
+ sd->scr[2] = 0x00;
+ sd->scr[3] = 0x00;
+ sd->scr[4] = 0x00;
+ sd->scr[5] = 0x00;
+ sd->scr[6] = 0x00;
+ sd->scr[7] = 0x00;
}
#define MID 0xaa
@@ -206,24 +209,25 @@
#define MDT_YR 2006
#define MDT_MON 2
-static void sd_set_cid(struct sd_state_s *sd) {
- sd->cid[0] = MID; /* Fake card manufacturer ID (MID) */
- sd->cid[1] = OID[0]; /* OEM/Application ID (OID) */
- sd->cid[2] = OID[1];
- sd->cid[3] = PNM[0]; /* Fake product name (PNM) */
- sd->cid[4] = PNM[1];
- sd->cid[5] = PNM[2];
- sd->cid[6] = PNM[3];
- sd->cid[7] = PNM[4];
- sd->cid[8] = PRV; /* Fake product revision (PRV) */
- sd->cid[9] = 0xde; /* Fake serial number (PSN) */
- sd->cid[10] = 0xad;
- sd->cid[11] = 0xbe;
- sd->cid[12] = 0xef;
- sd->cid[13] = 0x00 | /* Manufacture date (MDT) */
- ((MDT_YR - 2000) / 10);
- sd->cid[14] = ((MDT_YR % 10) << 4) | MDT_MON;
- sd->cid[15] = (sd_crc7(sd->cid, 15) << 1) | 1;
+static void sd_set_cid(SDState *sd)
+{
+ sd->cid[0] = MID; /* Fake card manufacturer ID (MID) */
+ sd->cid[1] = OID[0]; /* OEM/Application ID (OID) */
+ sd->cid[2] = OID[1];
+ sd->cid[3] = PNM[0]; /* Fake product name (PNM) */
+ sd->cid[4] = PNM[1];
+ sd->cid[5] = PNM[2];
+ sd->cid[6] = PNM[3];
+ sd->cid[7] = PNM[4];
+ sd->cid[8] = PRV; /* Fake product revision (PRV) */
+ sd->cid[9] = 0xde; /* Fake serial number (PSN) */
+ sd->cid[10] = 0xad;
+ sd->cid[11] = 0xbe;
+ sd->cid[12] = 0xef;
+ sd->cid[13] = 0x00 | /* Manufacture date (MDT) */
+ ((MDT_YR - 2000) / 10);
+ sd->cid[14] = ((MDT_YR % 10) << 4) | MDT_MON;
+ sd->cid[15] = (sd_crc7(sd->cid, 15) << 1) | 1;
}
#define HWBLOCK_SHIFT 9 /* 512 bytes */
@@ -235,1031 +239,1033 @@
#define WPGROUP_SIZE (1 << (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT))
static const uint8_t sd_csd_rw_mask[16] = {
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xfe,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xfe,
};
-static void sd_set_csd(struct sd_state_s *sd, uint32_t size) {
- uint32_t csize = (size >> (CMULT_SHIFT + HWBLOCK_SHIFT)) - 1;
- uint32_t sectsize = (1 << (SECTOR_SHIFT + 1)) - 1;
- uint32_t wpsize = (1 << (WPGROUP_SHIFT + 1)) - 1;
+static void sd_set_csd(SDState *sd, uint32_t size)
+{
+ uint32_t csize = (size >> (CMULT_SHIFT + HWBLOCK_SHIFT)) - 1;
+ uint32_t sectsize = (1 << (SECTOR_SHIFT + 1)) - 1;
+ uint32_t wpsize = (1 << (WPGROUP_SHIFT + 1)) - 1;
- sd->csd[0] = 0x00; /* CSD structure */
- sd->csd[1] = 0x26; /* Data read access-time-1 */
- sd->csd[2] = 0x00; /* Data read access-time-2 */
- sd->csd[3] = 0x5a; /* Max. data transfer rate */
- sd->csd[4] = 0x5f; /* Card Command Classes */
- sd->csd[5] = 0x50 | /* Max. read data block length */
- HWBLOCK_SHIFT;
- sd->csd[6] = 0xe0 | /* Partial block for read allowed */
- ((csize >> 10) & 0x03);
- sd->csd[7] = 0x00 | /* Device size */
- ((csize >> 2) & 0xff);
- sd->csd[8] = 0x3f | /* Max. read current */
- ((csize << 6) & 0xc0);
- sd->csd[9] = 0xfc | /* Max. write current */
- ((CMULT_SHIFT - 2) >> 1);
- sd->csd[10] = 0x40 | /* Erase sector size */
- (((CMULT_SHIFT - 2) << 7) & 0x80) | (sectsize >> 1);
- sd->csd[11] = 0x00 | /* Write protect group size */
- ((sectsize << 7) & 0x80) | wpsize;
- sd->csd[12] = 0x90 | /* Write speed factor */
- (HWBLOCK_SHIFT >> 2);
- sd->csd[13] = 0x20 | /* Max. write data block length */
- ((HWBLOCK_SHIFT << 6) & 0xc0);
- sd->csd[14] = 0x00; /* File format group */
- sd->csd[15] = (sd_crc7(sd->csd, 15) << 1) | 1;
+ sd->csd[0] = 0x00; /* CSD structure */
+ sd->csd[1] = 0x26; /* Data read access-time-1 */
+ sd->csd[2] = 0x00; /* Data read access-time-2 */
+ sd->csd[3] = 0x5a; /* Max. data transfer rate */
+ sd->csd[4] = 0x5f; /* Card Command Classes */
+ sd->csd[5] = 0x50 | /* Max. read data block length */
+ HWBLOCK_SHIFT;
+ sd->csd[6] = 0xe0 | /* Partial block for read allowed */
+ ((csize >> 10) & 0x03);
+ sd->csd[7] = 0x00 | /* Device size */
+ ((csize >> 2) & 0xff);
+ sd->csd[8] = 0x3f | /* Max. read current */
+ ((csize << 6) & 0xc0);
+ sd->csd[9] = 0xfc | /* Max. write current */
+ ((CMULT_SHIFT - 2) >> 1);
+ sd->csd[10] = 0x40 | /* Erase sector size */
+ (((CMULT_SHIFT - 2) << 7) & 0x80) | (sectsize >> 1);
+ sd->csd[11] = 0x00 | /* Write protect group size */
+ ((sectsize << 7) & 0x80) | wpsize;
+ sd->csd[12] = 0x90 | /* Write speed factor */
+ (HWBLOCK_SHIFT >> 2);
+ sd->csd[13] = 0x20 | /* Max. write data block length */
+ ((HWBLOCK_SHIFT << 6) & 0xc0);
+ sd->csd[14] = 0x00; /* File format group */
+ sd->csd[15] = (sd_crc7(sd->csd, 15) << 1) | 1;
}
-static void sd_set_rca(struct sd_state_s *sd) {
- sd->rca += 0x4567;
+static void sd_set_rca(SDState *sd)
+{
+ sd->rca += 0x4567;
}
#define CARD_STATUS_A 0x02004100
#define CARD_STATUS_B 0x00c01e00
#define CARD_STATUS_C 0xfd39a028
-static void sd_set_cardstatus(struct sd_state_s *sd) {
- sd->card_status = 0x00000100;
+static void sd_set_cardstatus(SDState *sd)
+{
+ sd->card_status = 0x00000100;
}
-static void sd_set_sdstatus(struct sd_state_s *sd) {
- memset(sd->sd_status, 0, 64);
+static void sd_set_sdstatus(SDState *sd)
+{
+ memset(sd->sd_status, 0, 64);
}
-static int sd_req_crc_validate(struct sd_request_s *req) {
- uint8_t buffer[5];
- buffer[0] = 0x40 | req->cmd;
- buffer[1] = (req->arg >> 24) & 0xff;
- buffer[2] = (req->arg >> 16) & 0xff;
- buffer[3] = (req->arg >> 8) & 0xff;
- buffer[4] = (req->arg >> 0) & 0xff;
- return 0;
- return sd_crc7(buffer, 5) != req->crc; /* TODO */
+static int sd_req_crc_validate(struct sd_request_s *req)
+{
+ uint8_t buffer[5];
+ buffer[0] = 0x40 | req->cmd;
+ buffer[1] = (req->arg >> 24) & 0xff;
+ buffer[2] = (req->arg >> 16) & 0xff;
+ buffer[3] = (req->arg >> 8) & 0xff;
+ buffer[4] = (req->arg >> 0) & 0xff;
+ return 0;
+ return sd_crc7(buffer, 5) != req->crc; /* TODO */
}
-void sd_response_r1_make(struct sd_state_s *sd,
- union sd_response_u *response, uint32_t last_status) {
- int buffer[5];
- uint32_t mask = CARD_STATUS_B ^ ILLEGAL_COMMAND;
+void sd_response_r1_make(SDState *sd,
+ uint8_t *response, uint32_t last_status)
+{
+ uint32_t mask = CARD_STATUS_B ^ ILLEGAL_COMMAND;
+ uint32_t status;
- response->r1.cmd = sd->current_cmd;
- response->r1.status = (sd->card_status & ~mask) | (last_status & mask);
- sd->card_status &= ~CARD_STATUS_C | APP_CMD;
+ status = (sd->card_status & ~mask) | (last_status & mask);
+ sd->card_status &= ~CARD_STATUS_C | APP_CMD;
- buffer[0] = 0x00 | response->r1.cmd;
- buffer[1] = (response->r1.status >> 24) & 0xff;
- buffer[2] = (response->r1.status >> 16) & 0xff;
- buffer[3] = (response->r1.status >> 8) & 0xff;
- buffer[4] = (response->r1.status >> 0) & 0xff;
- response->r1.crc = sd_crc7(buffer, 5);
+ response[0] = (status >> 24) & 0xff;
+ response[1] = (status >> 16) & 0xff;
+ response[2] = (status >> 8) & 0xff;
+ response[3] = (status >> 0) & 0xff;
}
-void sd_response_r2_make(struct sd_state_s *sd,
- union sd_response_u *response) {
- response->r2.reg[7] |= 0x01;
+void sd_response_r3_make(SDState *sd, uint8_t *response)
+{
+ response[0] = (sd->ocr >> 24) & 0xff;
+ response[1] = (sd->ocr >> 16) & 0xff;
+ response[2] = (sd->ocr >> 8) & 0xff;
+ response[3] = (sd->ocr >> 0) & 0xff;
}
-void sd_response_r3_make(struct sd_state_s *sd,
- union sd_response_u *response) {
- response->r3.ocr_reg = sd->ocr;
-}
+void sd_response_r6_make(SDState *sd, uint8_t *response)
+{
+ uint16_t arg;
+ uint16_t status;
-void sd_response_r6_make(struct sd_state_s *sd,
- union sd_response_u *response) {
- int buffer[5];
+ arg = sd->rca;
+ status = ((sd->card_status >> 8) & 0xc000) |
+ ((sd->card_status >> 6) & 0x2000) |
+ (sd->card_status & 0x1fff);
- response->r6.cmd = sd->current_cmd;
- response->r6.arg = sd->rca;
- response->r6.status =
- ((sd->card_status >> 8) & 0xc000) |
- ((sd->card_status >> 6) & 0x2000) |
- (sd->card_status & 0x1fff);
-
- buffer[0] = 0x00 | response->r6.cmd;
- buffer[1] = (response->r6.arg >> 8) & 0xff;
- buffer[2] = (response->r6.arg >> 0) & 0xff;
- buffer[3] = (response->r6.status >> 8) & 0xff;
- buffer[4] = (response->r6.status >> 0) & 0xff;
- response->r6.crc = sd_crc7(buffer, 5);
+ response[0] = (arg >> 8) & 0xff;
+ response[1] = arg & 0xff;
+ response[2] = (status >> 8) & 0xff;
+ response[3] = status & 0xff;
}
-static void sd_reset(struct sd_state_s *sd, BlockDriverState *bdrv) {
- uint32_t size;
- uint64_t sect;
+static void sd_reset(SDState *sd, BlockDriverState *bdrv)
+{
+ uint32_t size;
+ uint64_t sect;
- bdrv_get_geometry(bdrv, §);
- sect <<= 9;
+ bdrv_get_geometry(bdrv, §);
+ sect <<= 9;
- if (sect > 0x40000000)
- size = 0x40000000; /* 1 gig */
- else
- size = sect + 1;
+ if (sect > 0x40000000)
+ size = 0x40000000; /* 1 gig */
+ else
+ size = sect + 1;
- sect = (size >> (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT)) + 1;
+ sect = (size >> (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT)) + 1;
- sd->state = sd_idle_state;
- sd->rca = 0x0000;
- sd_set_ocr(sd);
- sd_set_scr(sd);
- sd_set_cid(sd);
- sd_set_csd(sd, size);
- sd_set_cardstatus(sd);
- sd_set_sdstatus(sd);
+ sd->state = sd_idle_state;
+ sd->rca = 0x0000;
+ sd_set_ocr(sd);
+ sd_set_scr(sd);
+ sd_set_cid(sd);
+ sd_set_csd(sd, size);
+ sd_set_cardstatus(sd);
+ sd_set_sdstatus(sd);
- sd->bdrv = bdrv;
+ sd->bdrv = bdrv;
- sd->wp_switch = bdrv_is_read_only(bdrv);
- sd->wp_groups = (int *) qemu_mallocz(sizeof(int) * sect);
- memset(sd->wp_groups, 0, sizeof(int) * sect);
- memset(sd->function_group, 0, sizeof(int) * 6);
- sd->erase_start = 0;
- sd->erase_end = 0;
- sd->size = size;
- sd->blk_len = 0x200;
- sd->pwd_len = 0;
+ sd->wp_switch = bdrv_is_read_only(bdrv);
+ sd->wp_groups = (int *) qemu_mallocz(sizeof(int) * sect);
+ memset(sd->wp_groups, 0, sizeof(int) * sect);
+ memset(sd->function_group, 0, sizeof(int) * 6);
+ sd->erase_start = 0;
+ sd->erase_end = 0;
+ sd->size = size;
+ sd->blk_len = 0x200;
+ sd->pwd_len = 0;
}
-static void sd_cardchange(void *opaque) {
- struct sd_state_s *sd = opaque;
- if (sd->inserted_cb)
- sd->inserted_cb(sd->opaque, bdrv_is_inserted(sd->bdrv));
- if (bdrv_is_inserted(sd->bdrv)) {
- sd_reset(sd, sd->bdrv);
- if (sd->readonly_cb)
- sd->readonly_cb(sd->opaque, sd->wp_switch);
- }
+static void sd_cardchange(void *opaque)
+{
+ SDState *sd = opaque;
+ if (sd->inserted_cb)
+ sd->inserted_cb(sd->opaque, bdrv_is_inserted(sd->bdrv));
+ if (bdrv_is_inserted(sd->bdrv)) {
+ sd_reset(sd, sd->bdrv);
+ if (sd->readonly_cb)
+ sd->readonly_cb(sd->opaque, sd->wp_switch);
+ }
}
-struct sd_state_s *sd_init() {
- struct sd_state_s *sd;
- BlockDriverState *bs = bdrv_new("sd");
- bdrv_set_type_hint(bs, BDRV_TYPE_FLOPPY);
+SDState *sd_init(BlockDriverState *bs)
+{
+ SDState *sd;
- if (sd_filename) {
- if (bdrv_open(bs, sd_filename,
- snapshot ? BDRV_O_SNAPSHOT : 0) < 0)
- fprintf(stderr, "%s: Couldn't open %s\n",
- __FUNCTION__, sd_filename);
- else
- qemu_key_check(bs, sd_filename);
- }
-
- sd = (struct sd_state_s *) qemu_mallocz(sizeof(struct sd_state_s));
- sd_reset(sd, bs);
- return sd;
+ sd = (SDState *) qemu_mallocz(sizeof(SDState));
+ sd_reset(sd, bs);
+ return sd;
}
-void sd_set_cb(struct sd_state_s *sd, void *opaque,
- void (*readonly_cb)(void *, int),
- void (*inserted_cb)(void *, int)) {
- sd->opaque = opaque;
- sd->readonly_cb = readonly_cb;
- sd->inserted_cb = inserted_cb;
- if (sd->readonly_cb)
- sd->readonly_cb(sd->opaque, bdrv_is_read_only(sd->bdrv));
- if (sd->inserted_cb)
- sd->inserted_cb(sd->opaque, bdrv_is_inserted(sd->bdrv));
- bdrv_set_change_cb(sd->bdrv, sd_cardchange, sd);
+void sd_set_cb(SDState *sd, void *opaque,
+ void (*readonly_cb)(void *, int),
+ void (*inserted_cb)(void *, int))
+{
+ sd->opaque = opaque;
+ sd->readonly_cb = readonly_cb;
+ sd->inserted_cb = inserted_cb;
+ if (sd->readonly_cb)
+ sd->readonly_cb(sd->opaque, bdrv_is_read_only(sd->bdrv));
+ if (sd->inserted_cb)
+ sd->inserted_cb(sd->opaque, bdrv_is_inserted(sd->bdrv));
+ bdrv_set_change_cb(sd->bdrv, sd_cardchange, sd);
}
-static void sd_erase(struct sd_state_s *sd) {
- int i, start, end;
- if (!sd->erase_start || !sd->erase_end) {
- sd->card_status |= ERASE_SEQ_ERROR;
- return;
- }
+static void sd_erase(SDState *sd)
+{
+ int i, start, end;
+ if (!sd->erase_start || !sd->erase_end) {
+ sd->card_status |= ERASE_SEQ_ERROR;
+ return;
+ }
- start = sd->erase_start >>
- (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT);
- end = sd->erase_end >>
- (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT);
- sd->erase_start = 0;
- sd->erase_end = 0;
- sd->csd[14] |= 0x40;
+ start = sd->erase_start >>
+ (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT);
+ end = sd->erase_end >>
+ (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT);
+ sd->erase_start = 0;
+ sd->erase_end = 0;
+ sd->csd[14] |= 0x40;
- for (i = start; i <= end; i ++)
- if (sd->wp_groups[i])
- sd->card_status |= WP_ERASE_SKIP;
+ for (i = start; i <= end; i ++)
+ if (sd->wp_groups[i])
+ sd->card_status |= WP_ERASE_SKIP;
}
-static uint32_t sd_wpbits(struct sd_state_s *sd, uint32_t addr) {
- uint32_t i, wpnum;
- uint32_t ret = 0;
+static uint32_t sd_wpbits(SDState *sd, uint32_t addr)
+{
+ uint32_t i, wpnum;
+ uint32_t ret = 0;
- wpnum = addr >> (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT);
+ wpnum = addr >> (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT);
- for (i = 0; i < 32; i ++, wpnum ++, addr += WPGROUP_SIZE)
- if (addr < sd->size && sd->wp_groups[wpnum])
- ret |= (1 << i);
+ for (i = 0; i < 32; i ++, wpnum ++, addr += WPGROUP_SIZE)
+ if (addr < sd->size && sd->wp_groups[wpnum])
+ ret |= (1 << i);
- return ret;
+ return ret;
}
-static void sd_function_switch(struct sd_state_s *sd, uint32_t arg) {
- int i, mode, new_func, crc;
- mode = !!(arg & 0x80000000);
+static void sd_function_switch(SDState *sd, uint32_t arg)
+{
+ int i, mode, new_func, crc;
+ mode = !!(arg & 0x80000000);
- sd->data[0] = 0x00; /* Maximum current consumption */
- sd->data[1] = 0x01;
- sd->data[2] = 0x80; /* Supported group 6 functions */
- sd->data[3] = 0x01;
- sd->data[4] = 0x80; /* Supported group 5 functions */
- sd->data[5] = 0x01;
- sd->data[6] = 0x80; /* Supported group 4 functions */
- sd->data[7] = 0x01;
- sd->data[8] = 0x80; /* Supported group 3 functions */
- sd->data[9] = 0x01;
- sd->data[10] = 0x80; /* Supported group 2 functions */
- sd->data[11] = 0x43;
- sd->data[12] = 0x80; /* Supported group 1 functions */
- sd->data[13] = 0x03;
- for (i = 0; i < 6; i ++) {
- new_func = (arg >> (i * 4)) & 0x0f;
- if (mode && new_func != 0x0f)
- sd->function_group[i] = new_func;
- sd->data[14 + (i >> 1)] = new_func << ((i * 4) & 4);
- }
- memset(&sd->data[17], 0, 47);
- crc = sd_crc16(sd->data, 64);
- sd->data[65] = crc >> 8;
- sd->data[66] = crc & 0xff;
+ sd->data[0] = 0x00; /* Maximum current consumption */
+ sd->data[1] = 0x01;
+ sd->data[2] = 0x80; /* Supported group 6 functions */
+ sd->data[3] = 0x01;
+ sd->data[4] = 0x80; /* Supported group 5 functions */
+ sd->data[5] = 0x01;
+ sd->data[6] = 0x80; /* Supported group 4 functions */
+ sd->data[7] = 0x01;
+ sd->data[8] = 0x80; /* Supported group 3 functions */
+ sd->data[9] = 0x01;
+ sd->data[10] = 0x80; /* Supported group 2 functions */
+ sd->data[11] = 0x43;
+ sd->data[12] = 0x80; /* Supported group 1 functions */
+ sd->data[13] = 0x03;
+ for (i = 0; i < 6; i ++) {
+ new_func = (arg >> (i * 4)) & 0x0f;
+ if (mode && new_func != 0x0f)
+ sd->function_group[i] = new_func;
+ sd->data[14 + (i >> 1)] = new_func << ((i * 4) & 4);
+ }
+ memset(&sd->data[17], 0, 47);
+ crc = sd_crc16(sd->data, 64);
+ sd->data[65] = crc >> 8;
+ sd->data[66] = crc & 0xff;
}
-static inline int sd_wp_addr(struct sd_state_s *sd, uint32_t addr) {
- return sd->wp_groups[addr >>
- (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT)];
+static inline int sd_wp_addr(SDState *sd, uint32_t addr)
+{
+ return sd->wp_groups[addr >>
+ (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT)];
}
-static void sd_lock_command(struct sd_state_s *sd) {
- int erase, lock, clr_pwd, set_pwd, pwd_len;
- erase = !!(sd->data[0] & 0x08);
- lock = sd->data[0] & 0x04;
- clr_pwd = sd->data[0] & 0x02;
- set_pwd = sd->data[0] & 0x01;
+static void sd_lock_command(SDState *sd)
+{
+ int erase, lock, clr_pwd, set_pwd, pwd_len;
+ erase = !!(sd->data[0] & 0x08);
+ lock = sd->data[0] & 0x04;
+ clr_pwd = sd->data[0] & 0x02;
+ set_pwd = sd->data[0] & 0x01;
- if (sd->blk_len > 1)
- pwd_len = sd->data[1];
- else
- pwd_len = 0;
+ if (sd->blk_len > 1)
+ pwd_len = sd->data[1];
+ else
+ pwd_len = 0;
- if (erase) {
- if (!(sd->card_status & CARD_IS_LOCKED) || sd->blk_len > 1 ||
- set_pwd || clr_pwd || lock || sd->wp_switch ||
- (sd->csd[14] & 0x20)) {
- sd->card_status |= LOCK_UNLOCK_FAILED;
- return;
- }
- memset(sd->wp_groups, 0, sizeof(int) * (sd->size >>
- (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT)));
- sd->csd[14] &= ~0x10;
- sd->card_status &= ~CARD_IS_LOCKED;
- sd->pwd_len = 0;
- /* Erasing the entire card here! */
- printf("SD: Card force-erased by CMD42\n");
- return;
- }
+ if (erase) {
+ if (!(sd->card_status & CARD_IS_LOCKED) || sd->blk_len > 1 ||
+ set_pwd || clr_pwd || lock || sd->wp_switch ||
+ (sd->csd[14] & 0x20)) {
+ sd->card_status |= LOCK_UNLOCK_FAILED;
+ return;
+ }
+ memset(sd->wp_groups, 0, sizeof(int) * (sd->size >>
+ (HWBLOCK_SHIFT + SECTOR_SHIFT + WPGROUP_SHIFT)));
+ sd->csd[14] &= ~0x10;
+ sd->card_status &= ~CARD_IS_LOCKED;
+ sd->pwd_len = 0;
+ /* Erasing the entire card here! */
+ printf("SD: Card force-erased by CMD42\n");
+ return;
+ }
- if (sd->blk_len < 2 + pwd_len ||
- pwd_len <= sd->pwd_len ||
- pwd_len > sd->pwd_len + 16) {
- sd->card_status |= LOCK_UNLOCK_FAILED;
- return;
- }
+ if (sd->blk_len < 2 + pwd_len ||
+ pwd_len <= sd->pwd_len ||
+ pwd_len > sd->pwd_len + 16) {
+ sd->card_status |= LOCK_UNLOCK_FAILED;
+ return;
+ }
- if (sd->pwd_len && memcmp(sd->pwd, sd->data + 2, sd->pwd_len)) {
- sd->card_status |= LOCK_UNLOCK_FAILED;
- return;
- }
+ if (sd->pwd_len && memcmp(sd->pwd, sd->data + 2, sd->pwd_len)) {
+ sd->card_status |= LOCK_UNLOCK_FAILED;
+ return;
+ }
- pwd_len -= sd->pwd_len;
- if ((pwd_len && !set_pwd) ||
- (clr_pwd && (set_pwd || lock)) ||
- (lock && !sd->pwd_len && !set_pwd) ||
- (!set_pwd && !clr_pwd &&
- (((sd->card_status & CARD_IS_LOCKED) && lock) ||
- (!(sd->card_status & CARD_IS_LOCKED) && !lock)))) {
- sd->card_status |= LOCK_UNLOCK_FAILED;
- return;
- }
+ pwd_len -= sd->pwd_len;
+ if ((pwd_len && !set_pwd) ||
+ (clr_pwd && (set_pwd || lock)) ||
+ (lock && !sd->pwd_len && !set_pwd) ||
+ (!set_pwd && !clr_pwd &&
+ (((sd->card_status & CARD_IS_LOCKED) && lock) ||
+ (!(sd->card_status & CARD_IS_LOCKED) && !lock)))) {
+ sd->card_status |= LOCK_UNLOCK_FAILED;
+ return;
+ }
- if (set_pwd) {
- memcpy(sd->pwd, sd->data + 2 + sd->pwd_len, pwd_len);
- sd->pwd_len = pwd_len;
- }
+ if (set_pwd) {
+ memcpy(sd->pwd, sd->data + 2 + sd->pwd_len, pwd_len);
+ sd->pwd_len = pwd_len;
+ }
- if (clr_pwd) {
- sd->pwd_len = 0;
- }
+ if (clr_pwd) {
+ sd->pwd_len = 0;
+ }
- if (lock)
- sd->card_status |= CARD_IS_LOCKED;
- else
- sd->card_status &= ~CARD_IS_LOCKED;
+ if (lock)
+ sd->card_status |= CARD_IS_LOCKED;
+ else
+ sd->card_status &= ~CARD_IS_LOCKED;
}
-static union sd_response_u sd_normal_command(struct sd_state_s *sd,
- struct sd_request_s req) {
- uint32_t rca = 0x0000;
- union sd_response_u response;
+static sd_rsp_type_t sd_normal_command(SDState *sd,
+ struct sd_request_s req)
+{
+ uint32_t rca = 0x0000;
- if (sd_cmd_type[req.cmd] == sd_ac || sd_cmd_type[req.cmd] == sd_adtc)
- rca = req.arg >> 16;
+ if (sd_cmd_type[req.cmd] == sd_ac || sd_cmd_type[req.cmd] == sd_adtc)
+ rca = req.arg >> 16;
- switch (req.cmd) {
- /* Basic commands (Class 0 and Class 1) */
- case 0: /* CMD0: GO_IDLE_STATE */
- switch (sd->state) {
- case sd_inactive_state:
- return response;
+ DPRINTF("CMD%d 0x%08x state %d\n", req.cmd, req.arg, sd->state);
+ switch (req.cmd) {
+ /* Basic commands (Class 0 and Class 1) */
+ case 0: /* CMD0: GO_IDLE_STATE */
+ switch (sd->state) {
+ case sd_inactive_state:
+ return sd_r0;
- default:
- sd->state = sd_idle_state;
- sd_reset(sd, sd->bdrv);
- return response;
- }
- break;
+ default:
+ sd->state = sd_idle_state;
+ sd_reset(sd, sd->bdrv);
+ return sd_r0;
+ }
+ break;
- case 2: /* CMD2: ALL_SEND_CID */
- switch (sd->state) {
- case sd_ready_state:
- sd->state = sd_identification_state;
- memcpy(response.r2.reg, sd->cid, 16);
- return response;
+ case 2: /* CMD2: ALL_SEND_CID */
+ switch (sd->state) {
+ case sd_ready_state:
+ sd->state = sd_identification_state;
+ return sd_r2_i;
- default:
- break;
- }
- break;
+ default:
+ break;
+ }
+ break;
- case 3: /* CMD3: SEND_RELATIVE_ADDR */
- switch (sd->state) {
- case sd_identification_state:
- case sd_standby_state:
- sd->state = sd_standby_state;
- sd_set_rca(sd);
- return response;
+ case 3: /* CMD3: SEND_RELATIVE_ADDR */
+ switch (sd->state) {
+ case sd_identification_state:
+ case sd_standby_state:
+ sd->state = sd_standby_state;
+ sd_set_rca(sd);
+ return sd_r6;
- default:
- break;
- }
- break;
+ default:
+ break;
+ }
+ break;
- case 4: /* CMD4: SEND_DSR */
- switch (sd->state) {
- case sd_standby_state:
- break;
+ case 4: /* CMD4: SEND_DSR */
+ switch (sd->state) {
+ case sd_standby_state:
+ break;
- default:
- break;
- }
- break;
+ default:
+ break;
+ }
+ break;
- case 6: /* CMD6: SWITCH_FUNCTION */
- switch (sd->mode) {
- case sd_data_transfer_mode:
- sd_function_switch(sd, req.arg);
- sd->state = sd_sendingdata_state;
- sd->data_start = 0;
- sd->data_offset = 0;
- return response;
+ case 6: /* CMD6: SWITCH_FUNCTION */
+ switch (sd->mode) {
+ case sd_data_transfer_mode:
+ sd_function_switch(sd, req.arg);
+ sd->state = sd_sendingdata_state;
+ sd->data_start = 0;
+ sd->data_offset = 0;
+ return sd_r1;
- default:
- break;
- }
- break;
+ default:
+ break;
+ }
+ break;
- case 7: /* CMD7: SELECT/DESELECT_CARD */
- switch (sd->state) {
- case sd_standby_state:
- if (sd->rca != rca)
- return response;
+ case 7: /* CMD7: SELECT/DESELECT_CARD */
+ switch (sd->state) {
+ case sd_standby_state:
+ if (sd->rca != rca)
+ return sd_r0;
- sd->state = sd_transfer_state;
- return response;
+ sd->state = sd_transfer_state;
+ return sd_r1b;
- case sd_transfer_state:
- case sd_sendingdata_state:
- if (sd->rca == rca)
- break;
+ case sd_transfer_state:
+ case sd_sendingdata_state:
+ if (sd->rca == rca)
+ break;
- sd->state = sd_standby_state;
- return response;
+ sd->state = sd_standby_state;
+ return sd_r1b;
- case sd_disconnect_state:
- if (sd->rca != rca)
- return response;
+ case sd_disconnect_state:
+ if (sd->rca != rca)
+ return sd_r0;
- sd->state = sd_programming_state;
- return response;
+ sd->state = sd_programming_state;
+ return sd_r1b;
- case sd_programming_state:
- if (sd->rca == rca)
- break;
+ case sd_programming_state:
+ if (sd->rca == rca)
+ break;
- sd->state = sd_disconnect_state;
- return response;
+ sd->state = sd_disconnect_state;
+ return sd_r1b;
- default:
- break;
- }
- break;
+ default:
+ break;
+ }
+ break;
- case 9: /* CMD9: SEND_CSD */
- switch (sd->state) {
- case sd_standby_state:
- if (sd->rca != rca)
- return response;
+ case 9: /* CMD9: SEND_CSD */
+ switch (sd->state) {
+ case sd_standby_state:
+ if (sd->rca != rca)
+ return sd_r0;
- memcpy(response.r2.reg, sd->csd, sizeof(sd->csd));
- return response;
+ return sd_r2_s;
- default:
- break;
- }
- break;
+ default:
+ break;
+ }
+ break;
- case 10: /* CMD10: SEND_CID */
- switch (sd->state) {
- case sd_standby_state:
- if (sd->rca != rca)
- return response;
+ case 10: /* CMD10: SEND_CID */
+ switch (sd->state) {
+ case sd_standby_state:
+ if (sd->rca != rca)
+ return sd_r0;
- memcpy(response.r2.reg, sd->cid, sizeof(sd->cid));
- return response;
+ return sd_r2_i;
- default:
- break;
- }
- break;
+ default:
+ break;
+ }
+ break;
- case 11: /* CMD11: READ_DAT_UNTIL_STOP */
- switch (sd->state) {
- case sd_transfer_state:
- sd->state = sd_sendingdata_state;
- sd->data_start = req.arg;
- sd->data_offset = 0;
+ case 11: /* CMD11: READ_DAT_UNTIL_STOP */
+ switch (sd->state) {
+ case sd_transfer_state:
+ sd->state = sd_sendingdata_state;
+ sd->data_start = req.arg;
+ sd->data_offset = 0;
- if (sd->data_start + sd->blk_len > sd->size)
- sd->card_status |= ADDRESS_ERROR;
- return response;
+ if (sd->data_start + sd->blk_len > sd->size)
+ sd->card_status |= ADDRESS_ERROR;
+ return sd_r0;
- default:
- break;
- }
- break;
+ default:
+ break;
+ }
+ break;
- case 12: /* CMD12: STOP_TRANSMISSION */
- switch (sd->state) {
- case sd_sendingdata_state:
- sd->state = sd_transfer_state;
- return response;
+ case 12: /* CMD12: STOP_TRANSMISSION */
+ switch (sd->state) {
+ case sd_sendingdata_state:
+ sd->state = sd_transfer_state;
+ return sd_r1b;
- case sd_receivingdata_state:
- sd->state = sd_programming_state;
- /* Bzzzzzzztt .... Operation complete. */
- sd->state = sd_transfer_state;
- return response;
+ case sd_receivingdata_state:
+ sd->state = sd_programming_state;
+ /* Bzzzzzzztt .... Operation complete. */
+ sd->state = sd_transfer_state;
+ return sd_r1b;
- default:
- break;
- }
- break;
+ default:
+ break;
+ }
+ break;
- case 13: /* CMD13: SEND_STATUS */
- switch (sd->mode) {
- case sd_data_transfer_mode:
- if (sd->rca != rca)
- return response;
+ case 13: /* CMD13: SEND_STATUS */
+ switch (sd->mode) {
+ case sd_data_transfer_mode:
+ if (sd->rca != rca)
+ return sd_r0;
- return response;
+ return sd_r1;
- default:
- break;
- }
- break;
+ default:
+ break;
+ }
+ break;
- case 15: /* CMD15: GO_INACTIVE_STATE */
- switch (sd->mode) {
- case sd_data_transfer_mode:
- if (sd->rca != rca)
- return response;
+ case 15: /* CMD15: GO_INACTIVE_STATE */
+ switch (sd->mode) {
+ case sd_data_transfer_mode:
+ if (sd->rca != rca)
+ return sd_r0;
- sd->state = sd_inactive_state;
- return response;
+ sd->state = sd_inactive_state;
+ return sd_r0;
- default:
- break;
- }
- break;
+ default:
+ break;
+ }
+ break;
- /* Block read commands (Classs 2) */
- case 16: /* CMD16: SET_BLOCKLEN */
- switch (sd->state) {
- case sd_transfer_state:
- if (req.arg > (1 << HWBLOCK_SHIFT))
- sd->card_status |= BLOCK_LEN_ERROR;
- else
- sd->blk_len = req.arg;
+ /* Block read commands (Classs 2) */
+ case 16: /* CMD16: SET_BLOCKLEN */
+ switch (sd->state) {
+ case sd_transfer_state:
+ if (req.arg > (1 << HWBLOCK_SHIFT))
+ sd->card_status |= BLOCK_LEN_ERROR;
+ else
+ sd->blk_len = req.arg;
- return response;
+ return sd_r1;
- default:
- break;
- }
- break;
+ default:
+ break;
+ }
+ break;
- case 17: /* CMD17: READ_SINGLE_BLOCK */
- switch (sd->state) {
- case sd_transfer_state:
- sd->state = sd_sendingdata_state;
- sd->data_start = req.arg;
- sd->data_offset = 0;
+ case 17: /* CMD17: READ_SINGLE_BLOCK */
+ switch (sd->state) {
+ case sd_transfer_state:
+ sd->state = sd_sendingdata_state;
+ sd->data_start = req.arg;
+ sd->data_offset = 0;
- if (sd->data_start + sd->blk_len > sd->size)
- sd->card_status |= ADDRESS_ERROR;
- return response;
+ if (sd->data_start + sd->blk_len > sd->size)
+ sd->card_status |= ADDRESS_ERROR;
+ return sd_r1;
- default:
- break;
- }
- break;
+ default:
+ break;
+ }
+ break;
- case 18: /* CMD18: READ_MULTIPLE_BLOCK */
- switch (sd->state) {
- case sd_transfer_state:
- sd->state = sd_sendingdata_state;
- sd->data_start = req.arg;
- sd->data_offset = 0;
+ case 18: /* CMD18: READ_MULTIPLE_BLOCK */
+ switch (sd->state) {
+ case sd_transfer_state:
+ sd->state = sd_sendingdata_state;
+ sd->data_start = req.arg;
+ sd->data_offset = 0;
- if (sd->data_start + sd->blk_len > sd->size)
- sd->card_status |= ADDRESS_ERROR;
- return response;
+ if (sd->data_start + sd->blk_len > sd->size)
+ sd->card_status |= ADDRESS_ERROR;
+ return sd_r1;
- default:
- break;
- }
- break;
+ default:
+ break;
+ }
+ break;
- /* Block write commands (Class 4) */
- case 24: /* CMD24: WRITE_SINGLE_BLOCK */
- switch (sd->state) {
- case sd_transfer_state:
- sd->state = sd_receivingdata_state;
- sd->data_start = req.arg;
- sd->data_offset = 0;
- sd->blk_written = 0;
+ /* Block write commands (Class 4) */
+ case 24: /* CMD24: WRITE_SINGLE_BLOCK */
+ switch (sd->state) {
+ case sd_transfer_state:
+ sd->state = sd_receivingdata_state;
+ sd->data_start = req.arg;
+ sd->data_offset = 0;
+ sd->blk_written = 0;
- if (sd->data_start + sd->blk_len > sd->size)
- sd->card_status |= ADDRESS_ERROR;
- if (sd_wp_addr(sd, sd->data_start))
- sd->card_status |= WP_VIOLATION;
- if (sd->csd[14] & 0x30)
- sd->card_status |= WP_VIOLATION;
- return response;
+ if (sd->data_start + sd->blk_len > sd->size)
+ sd->card_status |= ADDRESS_ERROR;
+ if (sd_wp_addr(sd, sd->data_start))
+ sd->card_status |= WP_VIOLATION;
+ if (sd->csd[14] & 0x30)
+ sd->card_status |= WP_VIOLATION;
+ return sd_r1;
- default:
- break;
- }
- break;
+ default:
+ break;
+ }
+ break;
- case 25: /* CMD25: WRITE_MULTIPLE_BLOCK */
- switch (sd->state) {
- case sd_transfer_state:
- sd->state = sd_receivingdata_state;
- sd->data_start = req.arg;
- sd->data_offset = 0;
- sd->blk_written = 0;
+ case 25: /* CMD25: WRITE_MULTIPLE_BLOCK */
+ switch (sd->state) {
+ case sd_transfer_state:
+ sd->state = sd_receivingdata_state;
+ sd->data_start = req.arg;
+ sd->data_offset = 0;
+ sd->blk_written = 0;
- if (sd->data_start + sd->blk_len > sd->size)
- sd->card_status |= ADDRESS_ERROR;
- if (sd_wp_addr(sd, sd->data_start))
- sd->card_status |= WP_VIOLATION;
- if (sd->csd[14] & 0x30)
- sd->card_status |= WP_VIOLATION;
- return response;
+ if (sd->data_start + sd->blk_len > sd->size)
+ sd->card_status |= ADDRESS_ERROR;
+ if (sd_wp_addr(sd, sd->data_start))
+ sd->card_status |= WP_VIOLATION;
+ if (sd->csd[14] & 0x30)
+ sd->card_status |= WP_VIOLATION;
+ return sd_r1;
- default:
- break;
- }
- break;
+ default:
+ break;
+ }
+ break;
- case 26: /* CMD26: PROGRAM_CID */
- switch (sd->state) {
- case sd_transfer_state:
- sd->state = sd_receivingdata_state;
- sd->data_start = 0;
- sd->data_offset = 0;
- return response;
+ case 26: /* CMD26: PROGRAM_CID */
+ switch (sd->state) {
+ case sd_transfer_state:
+ sd->state = sd_receivingdata_state;
+ sd->data_start = 0;
+ sd->data_offset = 0;
+ return sd_r1;
- default:
- break;
- }
- break;
+ default:
+ break;
+ }
+ break;
- case 27: /* CMD27: PROGRAM_CSD */
- switch (sd->state) {
- case sd_transfer_state:
- sd->state = sd_receivingdata_state;
- sd->data_start = 0;
- sd->data_offset = 0;
- return response;
+ case 27: /* CMD27: PROGRAM_CSD */
+ switch (sd->state) {
+ case sd_transfer_state:
+ sd->state = sd_receivingdata_state;
+ sd->data_start = 0;
+ sd->data_offset = 0;
+ return sd_r1;
- default:
- break;
- }
- break;
+ default:
+ break;
+ }
+ break;
- /* Write protection (Class 6) */
- case 28: /* CMD28: SET_WRITE_PROT */
- switch (sd->state) {
- case sd_transfer_state:
- if (req.arg >= sd->size) {
- sd->card_status = ADDRESS_ERROR;
- return response;
- }
+ /* Write protection (Class 6) */
+ case 28: /* CMD28: SET_WRITE_PROT */
+ switch (sd->state) {
+ case sd_transfer_state:
+ if (req.arg >= sd->size) {
+ sd->card_status = ADDRESS_ERROR;
+ return sd_r1b;
+ }
- sd->state = sd_programming_state;
- sd->wp_groups[req.arg >> (HWBLOCK_SHIFT +
- SECTOR_SHIFT + WPGROUP_SHIFT)] = 1;
- /* Bzzzzzzztt .... Operation complete. */
- sd->state = sd_transfer_state;
- return response;
+ sd->state = sd_programming_state;
+ sd->wp_groups[req.arg >> (HWBLOCK_SHIFT +
+ SECTOR_SHIFT + WPGROUP_SHIFT)] = 1;
+ /* Bzzzzzzztt .... Operation complete. */
+ sd->state = sd_transfer_state;
+ return sd_r1b;
- default:
- break;
- }
- break;
+ default:
+ break;
+ }
+ break;
- case 29: /* CMD29: CLR_WRITE_PROT */
- switch (sd->state) {
- case sd_transfer_state:
- if (req.arg >= sd->size) {
- sd->card_status = ADDRESS_ERROR;
- return response;
- }
+ case 29: /* CMD29: CLR_WRITE_PROT */
+ switch (sd->state) {
+ case sd_transfer_state:
+ if (req.arg >= sd->size) {
+ sd->card_status = ADDRESS_ERROR;
+ return sd_r1b;
+ }
- sd->state = sd_programming_state;
- sd->wp_groups[req.arg >> (HWBLOCK_SHIFT +
- SECTOR_SHIFT + WPGROUP_SHIFT)] = 0;
- /* Bzzzzzzztt .... Operation complete. */
- sd->state = sd_transfer_state;
- return response;
+ sd->state = sd_programming_state;
+ sd->wp_groups[req.arg >> (HWBLOCK_SHIFT +
+ SECTOR_SHIFT + WPGROUP_SHIFT)] = 0;
+ /* Bzzzzzzztt .... Operation complete. */
+ sd->state = sd_transfer_state;
+ return sd_r1b;
- default:
- break;
- }
- break;
+ default:
+ break;
+ }
+ break;
- case 30: /* CMD30: SEND_WRITE_PROT */
- switch (sd->state) {
- case sd_transfer_state:
- sd->state = sd_sendingdata_state;
- *(uint32_t *) sd->data = sd_wpbits(sd, req.arg);
- sd->data_start = req.arg;
- sd->data_offset = 0;
- return response;
+ case 30: /* CMD30: SEND_WRITE_PROT */
+ switch (sd->state) {
+ case sd_transfer_state:
+ sd->state = sd_sendingdata_state;
+ *(uint32_t *) sd->data = sd_wpbits(sd, req.arg);
+ sd->data_start = req.arg;
+ sd->data_offset = 0;
+ return sd_r1b;
- default:
- break;
- }
- break;
+ default:
+ break;
+ }
+ break;
- /* Erase commands (Class 5) */
- case 32: /* CMD32: ERASE_WR_BLK_START */
- switch (sd->state) {
- case sd_transfer_state:
- sd->erase_start = req.arg;
- return response;
+ /* Erase commands (Class 5) */
+ case 32: /* CMD32: ERASE_WR_BLK_START */
+ switch (sd->state) {
+ case sd_transfer_state:
+ sd->erase_start = req.arg;
+ return sd_r1;
- default:
- break;
- }
- break;
+ default:
+ break;
+ }
+ break;
- case 33: /* CMD33: ERASE_WR_BLK_END */
- switch (sd->state) {
- case sd_transfer_state:
- sd->erase_end = req.arg;
- return response;
+ case 33: /* CMD33: ERASE_WR_BLK_END */
+ switch (sd->state) {
+ case sd_transfer_state:
+ sd->erase_end = req.arg;
+ return sd_r1;
- default:
- break;
- }
- break;
+ default:
+ break;
+ }
+ break;
- case 38: /* CMD38: ERASE */
- switch (sd->state) {
- case sd_transfer_state:
- if (sd->csd[14] & 0x30) {
- sd->card_status |= WP_VIOLATION;
- return response;
- }
+ case 38: /* CMD38: ERASE */
+ switch (sd->state) {
+ case sd_transfer_state:
+ if (sd->csd[14] & 0x30) {
+ sd->card_status |= WP_VIOLATION;
+ return sd_r1b;
+ }
- sd->state = sd_programming_state;
- sd_erase(sd);
- /* Bzzzzzzztt .... Operation complete. */
- sd->state = sd_transfer_state;
- return response;
+ sd->state = sd_programming_state;
+ sd_erase(sd);
+ /* Bzzzzzzztt .... Operation complete. */
+ sd->state = sd_transfer_state;
+ return sd_r1b;
- default:
- break;
- }
- break;
+ default:
+ break;
+ }
+ break;
- /* Lock card commands (Class 7) */
- case 42: /* CMD42: LOCK_UNLOCK */
- switch (sd->state) {
- case sd_transfer_state:
- sd->state = sd_receivingdata_state;
- sd->data_start = 0;
- sd->data_offset = 0;
- return response;
+ /* Lock card commands (Class 7) */
+ case 42: /* CMD42: LOCK_UNLOCK */
+ switch (sd->state) {
+ case sd_transfer_state:
+ sd->state = sd_receivingdata_state;
+ sd->data_start = 0;
+ sd->data_offset = 0;
+ return sd_r1;
- default:
- break;
- }
- break;
+ default:
+ break;
+ }
+ break;
- /* Application specific commands (Class 8) */
- case 55: /* CMD55: APP_CMD */
- if (sd->rca != rca)
- return response;
+ /* Application specific commands (Class 8) */
+ case 55: /* CMD55: APP_CMD */
+ if (sd->rca != rca)
+ return sd_r0;
- sd->card_status |= APP_CMD;
- return response;
+ sd->card_status |= APP_CMD;
+ return sd_r1;
- case 56: /* CMD56: GEN_CMD */
- printf("SD: GEN_CMD 0x%08x\n", req.arg);
+ case 56: /* CMD56: GEN_CMD */
+ printf("SD: GEN_CMD 0x%08x\n", req.arg);
- switch (sd->state) {
- case sd_transfer_state:
- sd->data_offset = 0;
- if (req.arg & 1)
- sd->state = sd_sendingdata_state;
- else
- sd->state = sd_receivingdata_state;
- return response;
+ switch (sd->state) {
+ case sd_transfer_state:
+ sd->data_offset = 0;
+ if (req.arg & 1)
+ sd->state = sd_sendingdata_state;
+ else
+ sd->state = sd_receivingdata_state;
+ return sd_r1;
- default:
- break;
- }
- break;
+ default:
+ break;
+ }
+ break;
- default:
- sd->card_status |= ILLEGAL_COMMAND;
+ default:
+ sd->card_status |= ILLEGAL_COMMAND;
- printf("SD: Unknown CMD%i\n", req.cmd);
- return response;
- }
+ printf("SD: Unknown CMD%i\n", req.cmd);
+ return sd_r0;
+ }
- sd->card_status |= ILLEGAL_COMMAND;
- printf("SD: CMD%i in a wrong state\n", req.cmd);
- return response;
+ sd->card_status |= ILLEGAL_COMMAND;
+ printf("SD: CMD%i in a wrong state\n", req.cmd);
+ return sd_r0;
}
-static union sd_response_u sd_app_command(struct sd_state_s *sd,
- struct sd_request_s req) {
- uint32_t rca;
- union sd_response_u response;
+static sd_rsp_type_t sd_app_command(SDState *sd,
+ struct sd_request_s req) {
+ uint32_t rca;
- if (sd_cmd_type[req.cmd] == sd_ac || sd_cmd_type[req.cmd] == sd_adtc)
- rca = req.arg >> 16;
+ if (sd_cmd_type[req.cmd] == sd_ac || sd_cmd_type[req.cmd] == sd_adtc)
+ rca = req.arg >> 16;
- switch (req.cmd) {
- case 6: /* ACMD6: SET_BUS_WIDTH */
- switch (sd->state) {
- case sd_transfer_state:
- sd->sd_status[0] &= 0x3f;
- sd->sd_status[0] |= (req.arg & 0x03) << 6;
- return response;
+ DPRINTF("ACMD%d 0x%08x\n", req.cmd, req.arg);
+ switch (req.cmd) {
+ case 6: /* ACMD6: SET_BUS_WIDTH */
+ switch (sd->state) {
+ case sd_transfer_state:
+ sd->sd_status[0] &= 0x3f;
+ sd->sd_status[0] |= (req.arg & 0x03) << 6;
+ return sd_r1;
- default:
- break;
- }
- break;
+ default:
+ break;
+ }
+ break;
- case 13: /* ACMD13: SD_STATUS */
- switch (sd->state) {
- case sd_transfer_state:
- sd->data_start = 0;
- sd->data_offset = 0;
- return response;
+ case 13: /* ACMD13: SD_STATUS */
+ switch (sd->state) {
+ case sd_transfer_state:
+ sd->data_start = 0;
+ sd->data_offset = 0;
+ return sd_r1;
- default:
- break;
- }
- break;
+ default:
+ break;
+ }
+ break;
- case 22: /* ACMD22: SEND_NUM_WR_BLOCKS */
- switch (sd->state) {
- case sd_transfer_state:
- *(uint32_t *) sd->data = sd->blk_written;
+ case 22: /* ACMD22: SEND_NUM_WR_BLOCKS */
+ switch (sd->state) {
+ case sd_transfer_state:
+ *(uint32_t *) sd->data = sd->blk_written;
- sd->data_start = 0;
- sd->data_offset = 0;
- return response;
+ sd->data_start = 0;
+ sd->data_offset = 0;
+ return sd_r1;
- default:
- break;
- }
- break;
+ default:
+ break;
+ }
+ break;
- case 23: /* ACMD23: SET_WR_BLK_ERASE_COUNT */
- switch (sd->state) {
- case sd_transfer_state:
- return response;
+ case 23: /* ACMD23: SET_WR_BLK_ERASE_COUNT */
+ switch (sd->state) {
+ case sd_transfer_state:
+ return sd_r1;
- default:
- break;
- }
- break;
+ default:
+ break;
+ }
+ break;
- case 41: /* ACMD41: SD_APP_OP_COND */
- switch (sd->state) {
- case sd_idle_state:
- /* We accept any voltage. 10000 V is nothing. */
- if (req.arg)
- sd->state = sd_ready_state;
+ case 41: /* ACMD41: SD_APP_OP_COND */
+ switch (sd->state) {
+ case sd_idle_state:
+ /* We accept any voltage. 10000 V is nothing. */
+ if (req.arg)
+ sd->state = sd_ready_state;
- return response;
+ return sd_r3;
- default:
- break;
- }
- break;
+ default:
+ break;
+ }
+ break;
- case 42: /* ACMD42: SET_CLR_CARD_DETECT */
- switch (sd->state) {
- case sd_transfer_state:
- /* Bringing in the 50KOhm pull-up resistor... Done. */
- return response;
+ case 42: /* ACMD42: SET_CLR_CARD_DETECT */
+ switch (sd->state) {
+ case sd_transfer_state:
+ /* Bringing in the 50KOhm pull-up resistor... Done. */
+ return sd_r1;
- default:
- break;
- }
- break;
+ default:
+ break;
+ }
+ break;
- case 51: /* ACMD51: SEND_SCR */
- switch (sd->state) {
- case sd_transfer_state:
- sd->state = sd_sendingdata_state;
- sd->data_start = 0;
- sd->data_offset = 0;
- return response;
+ case 51: /* ACMD51: SEND_SCR */
+ switch (sd->state) {
+ case sd_transfer_state:
+ sd->state = sd_sendingdata_state;
+ sd->data_start = 0;
+ sd->data_offset = 0;
+ return sd_r1;
- default:
- break;
- }
- break;
+ default:
+ break;
+ }
+ break;
- default:
- /* Fall back to standard commands. */
- sd->card_status &= ~APP_CMD;
- return sd_normal_command(sd, req);
- }
+ default:
+ /* Fall back to standard commands. */
+ sd->card_status &= ~APP_CMD;
+ return sd_normal_command(sd, req);
+ }
- printf("SD: ACMD%i in a wrong state\n", req.cmd);
- return response;
+ printf("SD: ACMD%i in a wrong state\n", req.cmd);
+ return sd_r0;
}
-union sd_response_u sd_write_cmdline(struct sd_state_s *sd,
- struct sd_request_s req, int *rsplen) {
- uint32_t last_status = sd->card_status;
- union sd_response_u response;
- sd_rsp_type_t rtype;
+int sd_do_command(SDState *sd, struct sd_request_s *req,
+ uint8_t *response) {
+ uint32_t last_status = sd->card_status;
+ sd_rsp_type_t rtype;
+ int rsplen;
- if (!bdrv_is_inserted(sd->bdrv)) {
- *rsplen = 0;
- return response;
- }
+ if (!bdrv_is_inserted(sd->bdrv)) {
+ return 0;
+ }
- if (sd_req_crc_validate(&req)) {
- sd->card_status &= ~COM_CRC_ERROR;
- *rsplen = 0;
- return response;
- }
+ if (sd_req_crc_validate(req)) {
+ sd->card_status &= ~COM_CRC_ERROR;
+ return 0;
+ }
- sd->card_status &= ~CARD_STATUS_B;
- sd_set_status(sd);
+ sd->card_status &= ~CARD_STATUS_B;
+ sd_set_status(sd);
- if (last_status & CARD_IS_LOCKED)
- if (((last_status & APP_CMD) &&
- (sd_acmd_type[req.cmd] == 0 ||
- sd_acmd_type[req.cmd] == 7 ||
- req.cmd == 41)) ||
- (!(last_status & APP_CMD) &&
- (sd_cmd_type[req.cmd] == 0 ||
- sd_cmd_type[req.cmd] == 7 ||
- req.cmd == 16 || req.cmd == 55))) {
- sd->card_status |= ILLEGAL_COMMAND;
- printf("SD: Card is locked\n");
- return response;
- }
+ if (last_status & CARD_IS_LOCKED)
+ if (((last_status & APP_CMD) &&
+ req->cmd == 41) ||
+ (!(last_status & APP_CMD) &&
+ (sd_cmd_class[req->cmd] == 0 ||
+ sd_cmd_class[req->cmd] == 7 ||
+ req->cmd == 16 || req->cmd == 55))) {
+ sd->card_status |= ILLEGAL_COMMAND;
+ printf("SD: Card is locked\n");
+ return 0;
+ }
- if (last_status & APP_CMD)
- response = sd_app_command(sd, req);
- else
- response = sd_normal_command(sd, req);
+ if (last_status & APP_CMD)
+ rtype = sd_app_command(sd, *req);
+ else
+ rtype = sd_normal_command(sd, *req);
- if (last_status & APP_CMD) {
- if (sd->card_status & APP_CMD) {
- rtype = sd_acmd_response[req.cmd];
- sd->card_status &= ~APP_CMD;
- } else
- rtype = sd_cmd_response[req.cmd];
- } else
- rtype = sd_cmd_response[req.cmd];
+ sd->current_cmd = req->cmd;
- sd->current_cmd = req.cmd;
+ switch (rtype) {
+ case sd_r1:
+ case sd_r1b:
+ sd_response_r1_make(sd, response, last_status);
+ rsplen = 4;
+ break;
- switch (rtype) {
- case sd_r1:
- case sd_r1b:
- sd_response_r1_make(sd, &response, last_status);
- *rsplen = 48;
- break;
+ case sd_r2_i:
+ memcpy(response, sd->cid, sizeof(sd->cid));
+ response[7] |= 1;
+ rsplen = 16;
+ break;
- case sd_r2:
- sd_response_r2_make(sd, &response);
- *rsplen = 128;
- break;
+ case sd_r2_s:
+ memcpy(response, sd->csd, sizeof(sd->csd));
+ response[7] |= 1;
+ rsplen = 16;
+ break;
- case sd_r3:
- sd_response_r3_make(sd, &response);
- *rsplen = 48;
- break;
+ case sd_r3:
+ sd_response_r3_make(sd, response);
+ rsplen = 4;
+ break;
- case sd_r6:
- sd_response_r6_make(sd, &response);
- *rsplen = 48;
- break;
+ case sd_r6:
+ sd_response_r6_make(sd, response);
+ rsplen = 4;
+ break;
- case sd_nore:
- default:
- *rsplen = 0;
- break;
- }
+ case sd_r0:
+ default:
+ rsplen = 0;
+ break;
+ }
- if (sd->card_status & ILLEGAL_COMMAND)
- *rsplen = 0;
+ if (sd->card_status & ILLEGAL_COMMAND)
+ rsplen = 0;
- return response;
+#ifdef DEBUG_SD
+ if (rsplen) {
+ int i;
+ DPRINTF("Response:");
+ for (i = 0; i < rsplen; i++)
+ printf(" %02x", response[i]);
+ printf(" state %d\n", sd->state);
+ } else {
+ DPRINTF("No response %d\n", sd->state);
+ }
+#endif
+
+ return rsplen;
}
/* No real need for 64 bit addresses here */
static void sd_blk_read(BlockDriverState *bdrv,
- void *data, uint32_t addr, uint32_t len) {
- uint8_t buf[512];
- uint32_t end = addr + len;
+ void *data, uint32_t addr, uint32_t len)
+{
+ uint8_t buf[512];
+ uint32_t end = addr + len;
- if (!bdrv || bdrv_read(bdrv, addr >> 9, buf, 1) == -1) {
- printf("sd_blk_read: read error on host side\n");
- return;
- }
+ if (!bdrv || bdrv_read(bdrv, addr >> 9, buf, 1) == -1) {
+ printf("sd_blk_read: read error on host side\n");
+ return;
+ }
- if (end > (addr & ~511) + 512) {
- memcpy(data, buf + (addr & 511), 512 - (addr & 511));
+ if (end > (addr & ~511) + 512) {
+ memcpy(data, buf + (addr & 511), 512 - (addr & 511));
- if (bdrv_read(bdrv, end >> 9, buf, 1) == -1) {
- printf("sd_blk_read: read error on host side\n");
- return;
- }
- memcpy(data + 512 - (addr & 511), buf, end & 511);
- } else
- memcpy(data, buf + (addr & 511), len);
+ if (bdrv_read(bdrv, end >> 9, buf, 1) == -1) {
+ printf("sd_blk_read: read error on host side\n");
+ return;
+ }
+ memcpy(data + 512 - (addr & 511), buf, end & 511);
+ } else
+ memcpy(data, buf + (addr & 511), len);
}
static void sd_blk_write(BlockDriverState *bdrv,
- void *data, uint32_t addr, uint32_t len) {
- uint8_t buf[512];
- uint32_t end = addr + len;
+ void *data, uint32_t addr, uint32_t len)
+{
+ uint8_t buf[512];
+ uint32_t end = addr + len;
- if ((addr & 511) || len < 512)
- if (!bdrv || bdrv_read(bdrv, addr >> 9, buf, 1) == -1) {
- printf("sd_blk_write: read error on host side\n");
- return;
- }
+ if ((addr & 511) || len < 512)
+ if (!bdrv || bdrv_read(bdrv, addr >> 9, buf, 1) == -1) {
+ printf("sd_blk_write: read error on host side\n");
+ return;
+ }
- if (end > (addr & ~511) + 512) {
- memcpy(buf + (addr & 511), data, 512 - (addr & 511));
- if (bdrv_write(bdrv, addr >> 9, buf, 1) == -1) {
- printf("sd_blk_write: write error on host side\n");
- return;
- }
+ if (end > (addr & ~511) + 512) {
+ memcpy(buf + (addr & 511), data, 512 - (addr & 511));
+ if (bdrv_write(bdrv, addr >> 9, buf, 1) == -1) {
+ printf("sd_blk_write: write error on host side\n");
+ return;
+ }
- if (bdrv_read(bdrv, end >> 9, buf, 1) == -1) {
- printf("sd_blk_write: read error on host side\n");
- return;
- }
- memcpy(buf, data + 512 - (addr & 511), end & 511);
- if (bdrv_write(bdrv, end >> 9, buf, 1) == -1)
- printf("sd_blk_write: write error on host side\n");
- } else {
- memcpy(buf + (addr & 511), data, len);
- if (!bdrv || bdrv_write(bdrv, addr >> 9, buf, 1) == -1)
- printf("sd_blk_write: write error on host side\n");
- }
+ if (bdrv_read(bdrv, end >> 9, buf, 1) == -1) {
+ printf("sd_blk_write: read error on host side\n");
+ return;
+ }
+ memcpy(buf, data + 512 - (addr & 511), end & 511);
+ if (bdrv_write(bdrv, end >> 9, buf, 1) == -1)
+ printf("sd_blk_write: write error on host side\n");
+ } else {
+ memcpy(buf + (addr & 511), data, len);
+ if (!bdrv || bdrv_write(bdrv, addr >> 9, buf, 1) == -1)
+ printf("sd_blk_write: write error on host side\n");
+ }
}
#define BLK_READ_BLOCK(a, len) sd_blk_read(sd->bdrv, sd->data, a, len)
@@ -1267,229 +1273,236 @@
#define APP_READ_BLOCK(a, len) memset(sd->data, 0xec, len)
#define APP_WRITE_BLOCK(a, len)
-void sd_write_datline(struct sd_state_s *sd, uint8_t value) {
- int i;
+void sd_write_data(SDState *sd, uint8_t value)
+{
+ int i;
- if (!sd->bdrv || !bdrv_is_inserted(sd->bdrv))
- return;
+ if (!sd->bdrv || !bdrv_is_inserted(sd->bdrv))
+ return;
- if (sd->state != sd_receivingdata_state) {
- printf("sd_write_datline: not in Receiving-Data state\n");
- return;
- }
+ if (sd->state != sd_receivingdata_state) {
+ printf("sd_write_data: not in Receiving-Data state\n");
+ return;
+ }
- if (sd->card_status & (ADDRESS_ERROR | WP_VIOLATION))
- return;
+ if (sd->card_status & (ADDRESS_ERROR | WP_VIOLATION))
+ return;
- switch (sd->current_cmd) {
- case 24: /* CMD24: WRITE_SINGLE_BLOCK */
- sd->data[sd->data_offset ++] = value;
- if (sd->data_offset >= sd->blk_len) {
- /* TODO: Check CRC before committing */
- sd->state = sd_programming_state;
- BLK_WRITE_BLOCK(sd->data_start, sd->data_offset);
- sd->blk_written ++;
- sd->csd[14] |= 0x40;
- /* Bzzzzzzztt .... Operation complete. */
- sd->state = sd_transfer_state;
- }
- break;
+ switch (sd->current_cmd) {
+ case 24: /* CMD24: WRITE_SINGLE_BLOCK */
+ sd->data[sd->data_offset ++] = value;
+ if (sd->data_offset >= sd->blk_len) {
+ /* TODO: Check CRC before committing */
+ sd->state = sd_programming_state;
+ BLK_WRITE_BLOCK(sd->data_start, sd->data_offset);
+ sd->blk_written ++;
+ sd->csd[14] |= 0x40;
+ /* Bzzzzzzztt .... Operation complete. */
+ sd->state = sd_transfer_state;
+ }
+ break;
- case 25: /* CMD25: WRITE_MULTIPLE_BLOCK */
- sd->data[sd->data_offset ++] = value;
- if (sd->data_offset >= sd->blk_len) {
- /* TODO: Check CRC before committing */
- sd->state = sd_programming_state;
- BLK_WRITE_BLOCK(sd->data_start, sd->data_offset);
- sd->blk_written ++;
- sd->data_start += sd->blk_len;
- sd->data_offset = 0;
- if (sd->data_start + sd->blk_len > sd->size) {
- sd->card_status |= ADDRESS_ERROR;
- break;
- }
- if (sd_wp_addr(sd, sd->data_start)) {
- sd->card_status |= WP_VIOLATION;
- break;
- }
- sd->csd[14] |= 0x40;
+ case 25: /* CMD25: WRITE_MULTIPLE_BLOCK */
+ sd->data[sd->data_offset ++] = value;
+ if (sd->data_offset >= sd->blk_len) {
+ /* TODO: Check CRC before committing */
+ sd->state = sd_programming_state;
+ BLK_WRITE_BLOCK(sd->data_start, sd->data_offset);
+ sd->blk_written ++;
+ sd->data_start += sd->blk_len;
+ sd->data_offset = 0;
+ if (sd->data_start + sd->blk_len > sd->size) {
+ sd->card_status |= ADDRESS_ERROR;
+ break;
+ }
+ if (sd_wp_addr(sd, sd->data_start)) {
+ sd->card_status |= WP_VIOLATION;
+ break;
+ }
+ sd->csd[14] |= 0x40;
- /* Bzzzzzzztt .... Operation complete. */
- sd->state = sd_receivingdata_state;
- }
- break;
+ /* Bzzzzzzztt .... Operation complete. */
+ sd->state = sd_receivingdata_state;
+ }
+ break;
- case 26: /* CMD26: PROGRAM_CID */
- sd->data[sd->data_offset ++] = value;
- if (sd->data_offset >= sizeof(sd->cid)) {
- /* TODO: Check CRC before committing */
- sd->state = sd_programming_state;
- for (i = 0; i < sizeof(sd->cid); i ++)
- if ((sd->cid[i] | 0x00) != sd->data[i])
- sd->card_status |= CID_CSD_OVERWRITE;
+ case 26: /* CMD26: PROGRAM_CID */
+ sd->data[sd->data_offset ++] = value;
+ if (sd->data_offset >= sizeof(sd->cid)) {
+ /* TODO: Check CRC before committing */
+ sd->state = sd_programming_state;
+ for (i = 0; i < sizeof(sd->cid); i ++)
+ if ((sd->cid[i] | 0x00) != sd->data[i])
+ sd->card_status |= CID_CSD_OVERWRITE;
- if (!(sd->card_status & CID_CSD_OVERWRITE))
- for (i = 0; i < sizeof(sd->cid); i ++) {
- sd->cid[i] |= 0x00;
- sd->cid[i] &= sd->data[i];
- }
- /* Bzzzzzzztt .... Operation complete. */
- sd->state = sd_transfer_state;
- }
- break;
+ if (!(sd->card_status & CID_CSD_OVERWRITE))
+ for (i = 0; i < sizeof(sd->cid); i ++) {
+ sd->cid[i] |= 0x00;
+ sd->cid[i] &= sd->data[i];
+ }
+ /* Bzzzzzzztt .... Operation complete. */
+ sd->state = sd_transfer_state;
+ }
+ break;
- case 27: /* CMD27: PROGRAM_CSD */
- sd->data[sd->data_offset ++] = value;
- if (sd->data_offset >= sizeof(sd->csd)) {
- /* TODO: Check CRC before committing */
- sd->state = sd_programming_state;
- for (i = 0; i < sizeof(sd->csd); i ++)
- if ((sd->csd[i] | sd_csd_rw_mask[i]) !=
- (sd->data[i] | sd_csd_rw_mask[i]))
- sd->card_status |= CID_CSD_OVERWRITE;
+ case 27: /* CMD27: PROGRAM_CSD */
+ sd->data[sd->data_offset ++] = value;
+ if (sd->data_offset >= sizeof(sd->csd)) {
+ /* TODO: Check CRC before committing */
+ sd->state = sd_programming_state;
+ for (i = 0; i < sizeof(sd->csd); i ++)
+ if ((sd->csd[i] | sd_csd_rw_mask[i]) !=
+ (sd->data[i] | sd_csd_rw_mask[i]))
+ sd->card_status |= CID_CSD_OVERWRITE;
- /* Copy flag (OTP) & Permanent write protect */
- if (sd->csd[14] & ~sd->data[14] & 0x60)
- sd->card_status |= CID_CSD_OVERWRITE;
+ /* Copy flag (OTP) & Permanent write protect */
+ if (sd->csd[14] & ~sd->data[14] & 0x60)
+ sd->card_status |= CID_CSD_OVERWRITE;
- if (!(sd->card_status & CID_CSD_OVERWRITE))
- for (i = 0; i < sizeof(sd->csd); i ++) {
- sd->csd[i] |= sd_csd_rw_mask[i];
- sd->csd[i] &= sd->data[i];
- }
- /* Bzzzzzzztt .... Operation complete. */
- sd->state = sd_transfer_state;
- }
- break;
+ if (!(sd->card_status & CID_CSD_OVERWRITE))
+ for (i = 0; i < sizeof(sd->csd); i ++) {
+ sd->csd[i] |= sd_csd_rw_mask[i];
+ sd->csd[i] &= sd->data[i];
+ }
+ /* Bzzzzzzztt .... Operation complete. */
+ sd->state = sd_transfer_state;
+ }
+ break;
- case 42: /* CMD42: LOCK_UNLOCK */
- sd->data[sd->data_offset ++] = value;
- if (sd->data_offset >= sd->blk_len) {
- /* TODO: Check CRC before committing */
- sd->state = sd_programming_state;
- sd_lock_command(sd);
- /* Bzzzzzzztt .... Operation complete. */
- sd->state = sd_transfer_state;
- }
- break;
+ case 42: /* CMD42: LOCK_UNLOCK */
+ sd->data[sd->data_offset ++] = value;
+ if (sd->data_offset >= sd->blk_len) {
+ /* TODO: Check CRC before committing */
+ sd->state = sd_programming_state;
+ sd_lock_command(sd);
+ /* Bzzzzzzztt .... Operation complete. */
+ sd->state = sd_transfer_state;
+ }
+ break;
- case 56: /* CMD56: GEN_CMD */
- sd->data[sd->data_offset ++] = value;
- if (sd->data_offset >= sd->blk_len) {
- APP_WRITE_BLOCK(sd->data_start, sd->data_offset);
- sd->state = sd_transfer_state;
- }
- break;
+ case 56: /* CMD56: GEN_CMD */
+ sd->data[sd->data_offset ++] = value;
+ if (sd->data_offset >= sd->blk_len) {
+ APP_WRITE_BLOCK(sd->data_start, sd->data_offset);
+ sd->state = sd_transfer_state;
+ }
+ break;
- default:
- printf("sd_write_datline: unknown command\n");
- break;
- }
+ default:
+ printf("sd_write_data: unknown command\n");
+ break;
+ }
}
-uint8_t sd_read_datline(struct sd_state_s *sd) {
- /* TODO: Append CRCs */
- uint8_t ret;
+uint8_t sd_read_data(SDState *sd)
+{
+ /* TODO: Append CRCs */
+ uint8_t ret;
- if (!sd->bdrv || !bdrv_is_inserted(sd->bdrv))
- return 0x00;
+ if (!sd->bdrv || !bdrv_is_inserted(sd->bdrv))
+ return 0x00;
- if (sd->state != sd_sendingdata_state) {
- printf("sd_read_datline: not in Sending-Data state\n");
- return 0x00;
- }
+ if (sd->state != sd_sendingdata_state) {
+ printf("sd_read_data: not in Sending-Data state\n");
+ return 0x00;
+ }
- if (sd->card_status & (ADDRESS_ERROR | WP_VIOLATION))
- return 0x00;
+ if (sd->card_status & (ADDRESS_ERROR | WP_VIOLATION))
+ return 0x00;
- switch (sd->current_cmd) {
- case 6: /* CMD6: SWITCH_FUNCTION */
- ret = sd->data[sd->data_offset ++];
+ switch (sd->current_cmd) {
+ case 6: /* CMD6: SWITCH_FUNCTION */
+ ret = sd->data[sd->data_offset ++];
- if (sd->data_offset >= 64)
- sd->state = sd_transfer_state;
- break;
+ if (sd->data_offset >= 64)
+ sd->state = sd_transfer_state;
+ break;
- case 11: /* CMD11: READ_DAT_UNTIL_STOP */
- if (sd->data_offset == 0)
- BLK_READ_BLOCK(sd->data_start, sd->blk_len);
- ret = sd->data[sd->data_offset ++];
+ case 11: /* CMD11: READ_DAT_UNTIL_STOP */
+ if (sd->data_offset == 0)
+ BLK_READ_BLOCK(sd->data_start, sd->blk_len);
+ ret = sd->data[sd->data_offset ++];
- if (sd->data_offset >= sd->blk_len) {
- sd->data_start += sd->blk_len;
- sd->data_offset = 0;
- if (sd->data_start + sd->blk_len > sd->size) {
- sd->card_status |= ADDRESS_ERROR;
- break;
- }
- }
- break;
+ if (sd->data_offset >= sd->blk_len) {
+ sd->data_start += sd->blk_len;
+ sd->data_offset = 0;
+ if (sd->data_start + sd->blk_len > sd->size) {
+ sd->card_status |= ADDRESS_ERROR;
+ break;
+ }
+ }
+ break;
- case 13: /* ACMD13: SD_STATUS */
- ret = sd->sd_status[sd->data_offset ++];
+ case 13: /* ACMD13: SD_STATUS */
+ ret = sd->sd_status[sd->data_offset ++];
- if (sd->data_offset >= sizeof(sd->sd_status))
- sd->state = sd_transfer_state;
- break;
+ if (sd->data_offset >= sizeof(sd->sd_status))
+ sd->state = sd_transfer_state;
+ break;
- case 17: /* CMD17: READ_SINGLE_BLOCK */
- if (sd->data_offset == 0)
- BLK_READ_BLOCK(sd->data_start, sd->blk_len);
- ret = sd->data[sd->data_offset ++];
+ case 17: /* CMD17: READ_SINGLE_BLOCK */
+ if (sd->data_offset == 0)
+ BLK_READ_BLOCK(sd->data_start, sd->blk_len);
+ ret = sd->data[sd->data_offset ++];
- if (sd->data_offset >= sd->blk_len)
- sd->state = sd_transfer_state;
- break;
+ if (sd->data_offset >= sd->blk_len)
+ sd->state = sd_transfer_state;
+ break;
- case 18: /* CMD18: READ_MULTIPLE_BLOCK */
- if (sd->data_offset == 0)
- BLK_READ_BLOCK(sd->data_start, sd->blk_len);
- ret = sd->data[sd->data_offset ++];
+ case 18: /* CMD18: READ_MULTIPLE_BLOCK */
+ if (sd->data_offset == 0)
+ BLK_READ_BLOCK(sd->data_start, sd->blk_len);
+ ret = sd->data[sd->data_offset ++];
- if (sd->data_offset >= sd->blk_len) {
- sd->data_start += sd->blk_len;
- sd->data_offset = 0;
- if (sd->data_start + sd->blk_len > sd->size) {
- sd->card_status |= ADDRESS_ERROR;
- break;
- }
- }
- break;
+ if (sd->data_offset >= sd->blk_len) {
+ sd->data_start += sd->blk_len;
+ sd->data_offset = 0;
+ if (sd->data_start + sd->blk_len > sd->size) {
+ sd->card_status |= ADDRESS_ERROR;
+ break;
+ }
+ }
+ break;
- case 22: /* ACMD22: SEND_NUM_WR_BLOCKS */
- ret = sd->data[sd->data_offset ++];
+ case 22: /* ACMD22: SEND_NUM_WR_BLOCKS */
+ ret = sd->data[sd->data_offset ++];
- if (sd->data_offset >= 4)
- sd->state = sd_transfer_state;
- break;
+ if (sd->data_offset >= 4)
+ sd->state = sd_transfer_state;
+ break;
- case 30: /* CMD30: SEND_WRITE_PROT */
- ret = sd->data[sd->data_offset ++];
+ case 30: /* CMD30: SEND_WRITE_PROT */
+ ret = sd->data[sd->data_offset ++];
- if (sd->data_offset >= 4)
- sd->state = sd_transfer_state;
- break;
+ if (sd->data_offset >= 4)
+ sd->state = sd_transfer_state;
+ break;
- case 51: /* ACMD51: SEND_SCR */
- ret = sd->scr[sd->data_offset ++];
+ case 51: /* ACMD51: SEND_SCR */
+ ret = sd->scr[sd->data_offset ++];
- if (sd->data_offset >= sizeof(sd->scr))
- sd->state = sd_transfer_state;
- break;
+ if (sd->data_offset >= sizeof(sd->scr))
+ sd->state = sd_transfer_state;
+ break;
- case 56: /* CMD56: GEN_CMD */
- if (sd->data_offset == 0)
- APP_READ_BLOCK(sd->data_start, sd->blk_len);
- ret = sd->data[sd->data_offset ++];
+ case 56: /* CMD56: GEN_CMD */
+ if (sd->data_offset == 0)
+ APP_READ_BLOCK(sd->data_start, sd->blk_len);
+ ret = sd->data[sd->data_offset ++];
- if (sd->data_offset >= sd->blk_len)
- sd->state = sd_transfer_state;
- break;
+ if (sd->data_offset >= sd->blk_len)
+ sd->state = sd_transfer_state;
+ break;
- default:
- printf("sd_read_datline: unknown command\n");
- return 0x00;
- }
+ default:
+ printf("sd_read_data: unknown command\n");
+ return 0x00;
+ }
- return ret;
+ return ret;
}
+
+int sd_data_ready(SDState *sd)
+{
+ return sd->state == sd_sendingdata_state;
+}
Modified: trunk/src/host/qemu-neo1973/hw/sd.h
===================================================================
--- trunk/src/host/qemu-neo1973/hw/sd.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/sd.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -54,76 +54,29 @@
#define AKE_SEQ_ERROR (1 << 3)
typedef enum {
- sd_none = -1,
- sd_bc = 0, /* broadcast -- no response */
- sd_bcr, /* broadcast with response */
- sd_ac, /* addressed -- no data transfer */
- sd_adtc, /* addressed with data transfer */
+ sd_none = -1,
+ sd_bc = 0, /* broadcast -- no response */
+ sd_bcr, /* broadcast with response */
+ sd_ac, /* addressed -- no data transfer */
+ sd_adtc, /* addressed with data transfer */
} sd_cmd_type_t;
-typedef enum {
- sd_nore = 0, /* no response */
- sd_r1, /* normal response command */
- sd_r2, /* CID, CSD registers */
- sd_r3, /* OCR register */
- sd_r6 = 6, /* Published RCA response */
- sd_r1b = -1,
-} sd_rsp_type_t;
-
struct sd_request_s {
- uint8_t cmd;
- uint32_t arg;
- uint8_t crc;
+ uint8_t cmd;
+ uint32_t arg;
+ uint8_t crc;
};
-struct sd_response_none_s {
-};
+typedef struct SDState SDState;
-struct sd_response_r1_s {
- uint8_t cmd;
- uint32_t status;
- uint8_t crc;
-};
+SDState *sd_init(BlockDriverState *bs);
+int sd_do_command(SDState *sd, struct sd_request_s *req,
+ uint8_t *response);
+void sd_write_data(SDState *sd, uint8_t value);
+uint8_t sd_read_data(SDState *sd);
+void sd_set_cb(SDState *sd, void *opaque,
+ void (*readonly_cb)(void *, int),
+ void (*inserted_cb)(void *, int));
+int sd_data_ready(SDState *sd);
-struct sd_response_r1b_s {
- uint8_t cmd;
- uint32_t status;
- uint8_t crc;
-};
-
-struct sd_response_r2_s {
- uint16_t reg[8];
-};
-
-struct sd_response_r3_s {
- uint32_t ocr_reg;
-};
-
-struct sd_response_r6_s {
- uint8_t cmd;
- uint16_t arg;
- uint16_t status;
- uint8_t crc;
-};
-
-union sd_response_u {
- struct sd_response_none_s none;
- struct sd_response_r1_s r1;
- struct sd_response_r1b_s r1b;
- struct sd_response_r2_s r2;
- struct sd_response_r3_s r3;
- struct sd_response_r6_s r6;
-};
-
-struct sd_state_s;
-
-struct sd_state_s *sd_init(void);
-union sd_response_u sd_write_cmdline(struct sd_state_s *sd,
- struct sd_request_s req, int *rsplen);
-void sd_write_datline(struct sd_state_s *sd, uint8_t value);
-uint8_t sd_read_datline(struct sd_state_s *sd);
-void sd_set_cb(struct sd_state_s *sd, void *opaque,
- void (*readonly_cb)(void *, int),
- void (*inserted_cb)(void *, int));
-
#endif /* __hw_sd_h */
Modified: trunk/src/host/qemu-neo1973/hw/serial.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/serial.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/serial.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -83,9 +83,7 @@
/* NOTE: this hidden state is necessary for tx irq generation as
it can be reset while reading iir */
int thr_ipending;
- SetIRQFunc *set_irq;
- void *irq_opaque;
- int irq;
+ qemu_irq irq;
CharDriverState *chr;
int last_break_enable;
target_ulong base;
@@ -102,9 +100,9 @@
s->iir = UART_IIR_NO_INT;
}
if (s->iir != UART_IIR_NO_INT) {
- s->set_irq(s->irq_opaque, s->irq, 1);
+ qemu_irq_raise(s->irq);
} else {
- s->set_irq(s->irq_opaque, s->irq, 0);
+ qemu_irq_lower(s->irq);
}
}
@@ -345,16 +343,13 @@
}
/* If fd is zero, it means that the serial device uses the console */
-SerialState *serial_init(SetIRQFunc *set_irq, void *opaque,
- int base, int irq, CharDriverState *chr)
+SerialState *serial_init(int base, qemu_irq irq, CharDriverState *chr)
{
SerialState *s;
s = qemu_mallocz(sizeof(SerialState));
if (!s)
return NULL;
- s->set_irq = set_irq;
- s->irq_opaque = opaque;
s->irq = irq;
s->lsr = UART_LSR_TEMT | UART_LSR_THRE;
s->iir = UART_IIR_NO_INT;
@@ -365,51 +360,51 @@
register_ioport_write(base, 8, 1, serial_ioport_write, s);
register_ioport_read(base, 8, 1, serial_ioport_read, s);
s->chr = chr;
- qemu_chr_add_read_handler(chr, serial_can_receive1, serial_receive1, s);
- qemu_chr_add_event_handler(chr, serial_event);
+ qemu_chr_add_handlers(chr, serial_can_receive1, serial_receive1,
+ serial_event, s);
return s;
}
/* Memory mapped interface */
-static uint32_t serial_mm_readb (void *opaque, target_phys_addr_t addr)
+uint32_t serial_mm_readb (void *opaque, target_phys_addr_t addr)
{
SerialState *s = opaque;
return serial_ioport_read(s, (addr - s->base) >> s->it_shift) & 0xFF;
}
-static void serial_mm_writeb (void *opaque,
- target_phys_addr_t addr, uint32_t value)
+void serial_mm_writeb (void *opaque,
+ target_phys_addr_t addr, uint32_t value)
{
SerialState *s = opaque;
serial_ioport_write(s, (addr - s->base) >> s->it_shift, value & 0xFF);
}
-static uint32_t serial_mm_readw (void *opaque, target_phys_addr_t addr)
+uint32_t serial_mm_readw (void *opaque, target_phys_addr_t addr)
{
SerialState *s = opaque;
return serial_ioport_read(s, (addr - s->base) >> s->it_shift) & 0xFFFF;
}
-static void serial_mm_writew (void *opaque,
- target_phys_addr_t addr, uint32_t value)
+void serial_mm_writew (void *opaque,
+ target_phys_addr_t addr, uint32_t value)
{
SerialState *s = opaque;
serial_ioport_write(s, (addr - s->base) >> s->it_shift, value & 0xFFFF);
}
-static uint32_t serial_mm_readl (void *opaque, target_phys_addr_t addr)
+uint32_t serial_mm_readl (void *opaque, target_phys_addr_t addr)
{
SerialState *s = opaque;
return serial_ioport_read(s, (addr - s->base) >> s->it_shift);
}
-static void serial_mm_writel (void *opaque,
- target_phys_addr_t addr, uint32_t value)
+void serial_mm_writel (void *opaque,
+ target_phys_addr_t addr, uint32_t value)
{
SerialState *s = opaque;
@@ -428,9 +423,9 @@
&serial_mm_writel,
};
-SerialState *serial_mm_init (SetIRQFunc *set_irq, void *opaque,
- target_ulong base, int it_shift,
- int irq, CharDriverState *chr)
+SerialState *serial_mm_init (target_ulong base, int it_shift,
+ qemu_irq irq, CharDriverState *chr,
+ int ioregister)
{
SerialState *s;
int s_io_memory;
@@ -438,8 +433,6 @@
s = qemu_mallocz(sizeof(SerialState));
if (!s)
return NULL;
- s->set_irq = set_irq;
- s->irq_opaque = opaque;
s->irq = irq;
s->lsr = UART_LSR_TEMT | UART_LSR_THRE;
s->iir = UART_IIR_NO_INT;
@@ -449,11 +442,13 @@
register_savevm("serial", base, 2, serial_save, serial_load, s);
- s_io_memory = cpu_register_io_memory(0, serial_mm_read,
- serial_mm_write, s);
- cpu_register_physical_memory(base, 8 << it_shift, s_io_memory);
+ if (ioregister) {
+ s_io_memory = cpu_register_io_memory(0, serial_mm_read,
+ serial_mm_write, s);
+ cpu_register_physical_memory(base, 8 << it_shift, s_io_memory);
+ }
s->chr = chr;
- qemu_chr_add_read_handler(chr, serial_can_receive1, serial_receive1, s);
- qemu_chr_add_event_handler(chr, serial_event);
+ qemu_chr_add_handlers(chr, serial_can_receive1, serial_receive1,
+ serial_event, s);
return s;
}
Modified: trunk/src/host/qemu-neo1973/hw/sh7750.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/sh7750.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/sh7750.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -299,9 +299,8 @@
}
s->serial1 = chr;
- qemu_chr_add_read_handler(chr, serial1_can_receive,
- serial1_receive, s);
- qemu_chr_add_event_handler(chr, serial1_event);
+ qemu_chr_add_handlers(chr, serial1_can_receive,
+ serial1_receive, serial1_event, s);
}
/**********************************************************************
@@ -415,9 +414,8 @@
}
s->serial2 = chr;
- qemu_chr_add_read_handler(chr, serial2_can_receive,
- serial2_receive, s);
- qemu_chr_add_event_handler(chr, serial2_event);
+ qemu_chr_add_handlers(chr, serial2_can_receive,
+ serial2_receive, serial1_event, s);
}
static void init_serial_ports(SH7750State * s)
Modified: trunk/src/host/qemu-neo1973/hw/shix.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/shix.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/shix.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -42,11 +42,6 @@
/* XXXXX */
}
-void pic_set_irq(int irq, int level)
-{
- /* XXXXX */
-}
-
void pic_info()
{
/* XXXXX */
@@ -70,7 +65,7 @@
void shix_init(int ram_size, int vga_ram_size, int boot_device,
DisplayState * ds, const char **fd_filename, int snapshot,
const char *kernel_filename, const char *kernel_cmdline,
- const char *initrd_filename)
+ const char *initrd_filename, const char *cpu_model)
{
int ret;
CPUState *env;
Modified: trunk/src/host/qemu-neo1973/hw/slavio_intctl.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/slavio_intctl.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/slavio_intctl.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -54,6 +54,7 @@
uint64_t irq_count[32];
#endif
CPUState *cpu_envs[MAX_CPUS];
+ const uint32_t *intbit_to_level;
} SLAVIO_INTCTLState;
#define INTCTL_MAXADDR 0xf
@@ -208,11 +209,6 @@
#endif
}
-static const uint32_t intbit_to_level[32] = {
- 2, 3, 5, 7, 9, 11, 0, 14, 3, 5, 7, 9, 11, 13, 12, 12,
- 6, 0, 4, 10, 8, 0, 11, 0, 0, 0, 0, 0, 15, 0, 15, 0,
-};
-
static void slavio_check_interrupts(void *opaque)
{
CPUState *env;
@@ -225,8 +221,8 @@
if (pending && !(s->intregm_disabled & 0x80000000)) {
for (i = 0; i < 32; i++) {
if (pending & (1 << i)) {
- if (max < intbit_to_level[i])
- max = intbit_to_level[i];
+ if (max < s->intbit_to_level[i])
+ max = s->intbit_to_level[i];
}
}
env = s->cpu_envs[s->target_cpu];
@@ -281,18 +277,19 @@
* "irq" here is the bit number in the system interrupt register to
* separate serial and keyboard interrupts sharing a level.
*/
-void slavio_pic_set_irq(void *opaque, int irq, int level)
+void slavio_set_irq(void *opaque, int irq, int level)
{
SLAVIO_INTCTLState *s = opaque;
DPRINTF("Set cpu %d irq %d level %d\n", s->target_cpu, irq, level);
if (irq < 32) {
uint32_t mask = 1 << irq;
- uint32_t pil = intbit_to_level[irq];
+ uint32_t pil = s->intbit_to_level[irq];
if (pil > 0) {
if (level) {
s->intregm_pending |= mask;
s->intreg_pending[s->target_cpu] |= 1 << pil;
+ slavio_check_interrupts(s);
}
else {
s->intregm_pending &= ~mask;
@@ -300,20 +297,19 @@
}
}
}
- slavio_check_interrupts(s);
}
-void slavio_pic_set_irq_cpu(void *opaque, int irq, int level, unsigned int cpu)
+void pic_set_irq_cpu(void *opaque, int irq, int level, unsigned int cpu)
{
SLAVIO_INTCTLState *s = opaque;
DPRINTF("Set cpu %d local irq %d level %d\n", cpu, irq, level);
if (cpu == (unsigned int)-1) {
- slavio_pic_set_irq(opaque, irq, level);
+ slavio_set_irq(opaque, irq, level);
return;
}
if (irq < 32) {
- uint32_t pil = intbit_to_level[irq];
+ uint32_t pil = s->intbit_to_level[irq];
if (pil > 0) {
if (level) {
s->intreg_pending[cpu] |= 1 << pil;
@@ -375,7 +371,9 @@
s->cpu_envs[cpu] = env;
}
-void *slavio_intctl_init(uint32_t addr, uint32_t addrg)
+void *slavio_intctl_init(uint32_t addr, uint32_t addrg,
+ const uint32_t *intbit_to_level,
+ qemu_irq **irq)
{
int slavio_intctl_io_memory, slavio_intctlm_io_memory, i;
SLAVIO_INTCTLState *s;
@@ -384,6 +382,7 @@
if (!s)
return NULL;
+ s->intbit_to_level = intbit_to_level;
for (i = 0; i < MAX_CPUS; i++) {
slavio_intctl_io_memory = cpu_register_io_memory(0, slavio_intctl_mem_read, slavio_intctl_mem_write, s);
cpu_register_physical_memory(addr + i * TARGET_PAGE_SIZE, INTCTL_MAXADDR, slavio_intctl_io_memory);
@@ -394,6 +393,7 @@
register_savevm("slavio_intctl", addr, 1, slavio_intctl_save, slavio_intctl_load, s);
qemu_register_reset(slavio_intctl_reset, s);
+ *irq = qemu_allocate_irqs(slavio_set_irq, s, 32);
slavio_intctl_reset(s);
return s;
}
Modified: trunk/src/host/qemu-neo1973/hw/slavio_misc.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/slavio_misc.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/slavio_misc.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -41,7 +41,7 @@
#endif
typedef struct MiscState {
- int irq;
+ qemu_irq irq;
uint8_t config;
uint8_t aux1, aux2;
uint8_t diag, mctrl, sysctrl;
@@ -54,9 +54,11 @@
MiscState *s = opaque;
if ((s->aux2 & 0x4) && (s->config & 0x8)) {
- pic_set_irq(s->irq, 1);
+ MISC_DPRINTF("Raise IRQ\n");
+ qemu_irq_raise(s->irq);
} else {
- pic_set_irq(s->irq, 0);
+ MISC_DPRINTF("Lower IRQ\n");
+ qemu_irq_lower(s->irq);
}
}
@@ -180,8 +182,10 @@
static void slavio_misc_save(QEMUFile *f, void *opaque)
{
MiscState *s = opaque;
+ int tmp;
- qemu_put_be32s(f, &s->irq);
+ tmp = 0;
+ qemu_put_be32s(f, &tmp); /* ignored, was IRQ. */
qemu_put_8s(f, &s->config);
qemu_put_8s(f, &s->aux1);
qemu_put_8s(f, &s->aux2);
@@ -193,11 +197,12 @@
static int slavio_misc_load(QEMUFile *f, void *opaque, int version_id)
{
MiscState *s = opaque;
+ int tmp;
if (version_id != 1)
return -EINVAL;
- qemu_get_be32s(f, &s->irq);
+ qemu_get_be32s(f, &tmp);
qemu_get_8s(f, &s->config);
qemu_get_8s(f, &s->aux1);
qemu_get_8s(f, &s->aux2);
@@ -207,7 +212,7 @@
return 0;
}
-void *slavio_misc_init(uint32_t base, int irq)
+void *slavio_misc_init(uint32_t base, qemu_irq irq)
{
int slavio_misc_io_memory;
MiscState *s;
Modified: trunk/src/host/qemu-neo1973/hw/slavio_serial.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/slavio_serial.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/slavio_serial.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -52,8 +52,6 @@
#ifdef DEBUG_SERIAL
#define SER_DPRINTF(fmt, args...) \
do { printf("SER: " fmt , ##args); } while (0)
-#define pic_set_irq(irq, level) \
-do { printf("SER: set_irq(%d): %d\n", (irq), (level)); pic_set_irq((irq),(level));} while (0)
#else
#define SER_DPRINTF(fmt, args...)
#endif
@@ -88,7 +86,7 @@
} SERIOQueue;
typedef struct ChannelState {
- int irq;
+ qemu_irq irq;
int reg;
int rxint, txint, rxint_under_svc, txint_under_svc;
chn_id_t chn; // this channel, A (base+4) or B (base+0)
@@ -110,6 +108,13 @@
static void serial_receive_byte(ChannelState *s, int ch);
static inline void set_txint(ChannelState *s);
+static void clear_queue(void *opaque)
+{
+ ChannelState *s = opaque;
+ SERIOQueue *q = &s->queue;
+ q->rptr = q->wptr = q->count = 0;
+}
+
static void put_queue(void *opaque, int b)
{
ChannelState *s = opaque;
@@ -139,7 +144,7 @@
q->rptr = 0;
q->count--;
}
- KBD_DPRINTF("channel %c get 0x%02x\n", CHN_C(s), val);
+ SER_DPRINTF("channel %c get 0x%02x\n", CHN_C(s), val);
if (q->count > 0)
serial_receive_byte(s, 0);
return val;
@@ -164,7 +169,8 @@
irq = slavio_serial_update_irq_chn(s);
irq |= slavio_serial_update_irq_chn(s->otherchn);
- pic_set_irq(s->irq, irq);
+ SER_DPRINTF("IRQ = %d\n", irq);
+ qemu_set_irq(s->irq, irq);
}
static void slavio_serial_reset_chn(ChannelState *s)
@@ -187,6 +193,7 @@
s->rx = s->tx = 0;
s->rxint = s->txint = 0;
s->rxint_under_svc = s->txint_under_svc = 0;
+ clear_queue(s);
}
static void slavio_serial_reset(void *opaque)
@@ -200,14 +207,21 @@
{
s->rxint = 0;
s->rxint_under_svc = 0;
- if (s->chn == chn_a)
+ if (s->chn == chn_a) {
+ if (s->wregs[9] & 0x10)
+ s->otherchn->rregs[2] = 0x60;
+ else
+ s->otherchn->rregs[2] = 0x06;
s->rregs[3] &= ~0x20;
- else
+ } else {
+ if (s->wregs[9] & 0x10)
+ s->rregs[2] = 0x60;
+ else
+ s->rregs[2] = 0x06;
s->otherchn->rregs[3] &= ~4;
+ }
if (s->txint)
set_txint(s);
- else
- s->rregs[2] = 6;
slavio_serial_update_irq(s);
}
@@ -216,27 +230,44 @@
s->rxint = 1;
if (!s->txint_under_svc) {
s->rxint_under_svc = 1;
- if (s->chn == chn_a)
- s->rregs[3] |= 0x20;
- else
- s->otherchn->rregs[3] |= 4;
- s->rregs[2] = 4;
- slavio_serial_update_irq(s);
+ if (s->chn == chn_a) {
+ if (s->wregs[9] & 0x10)
+ s->otherchn->rregs[2] = 0x30;
+ else
+ s->otherchn->rregs[2] = 0x0c;
+ } else {
+ if (s->wregs[9] & 0x10)
+ s->rregs[2] = 0x20;
+ else
+ s->rregs[2] = 0x04;
+ }
}
+ if (s->chn == chn_a)
+ s->rregs[3] |= 0x20;
+ else
+ s->otherchn->rregs[3] |= 4;
+ slavio_serial_update_irq(s);
}
static inline void clr_txint(ChannelState *s)
{
s->txint = 0;
s->txint_under_svc = 0;
- if (s->chn == chn_a)
+ if (s->chn == chn_a) {
+ if (s->wregs[9] & 0x10)
+ s->otherchn->rregs[2] = 0x60;
+ else
+ s->otherchn->rregs[2] = 0x06;
s->rregs[3] &= ~0x10;
- else
+ } else {
+ if (s->wregs[9] & 0x10)
+ s->rregs[2] = 0x60;
+ else
+ s->rregs[2] = 0x06;
s->otherchn->rregs[3] &= ~2;
+ }
if (s->rxint)
set_rxint(s);
- else
- s->rregs[2] = 6;
slavio_serial_update_irq(s);
}
@@ -245,13 +276,20 @@
s->txint = 1;
if (!s->rxint_under_svc) {
s->txint_under_svc = 1;
- if (s->chn == chn_a)
- s->rregs[3] |= 0x10;
- else
- s->otherchn->rregs[3] |= 2;
- s->rregs[2] = 0;
- slavio_serial_update_irq(s);
+ if (s->chn == chn_a) {
+ if (s->wregs[9] & 0x10)
+ s->otherchn->rregs[2] = 0x10;
+ else
+ s->otherchn->rregs[2] = 0x08;
+ } else {
+ s->rregs[2] = 0;
+ }
}
+ if (s->chn == chn_a)
+ s->rregs[3] |= 0x10;
+ else
+ s->otherchn->rregs[3] |= 2;
+ slavio_serial_update_irq(s);
}
static void slavio_serial_update_parameters(ChannelState *s)
@@ -492,7 +530,9 @@
static void slavio_serial_save_chn(QEMUFile *f, ChannelState *s)
{
- qemu_put_be32s(f, &s->irq);
+ int tmp;
+ tmp = 0;
+ qemu_put_be32s(f, &tmp); /* unused, was IRQ. */
qemu_put_be32s(f, &s->reg);
qemu_put_be32s(f, &s->rxint);
qemu_put_be32s(f, &s->txint);
@@ -514,10 +554,12 @@
static int slavio_serial_load_chn(QEMUFile *f, ChannelState *s, int version_id)
{
+ int tmp;
+
if (version_id > 2)
return -EINVAL;
- qemu_get_be32s(f, &s->irq);
+ qemu_get_be32s(f, &tmp); /* unused */
qemu_get_be32s(f, &s->reg);
qemu_get_be32s(f, &s->rxint);
qemu_get_be32s(f, &s->txint);
@@ -545,7 +587,8 @@
}
-SerialState *slavio_serial_init(int base, int irq, CharDriverState *chr1, CharDriverState *chr2)
+SerialState *slavio_serial_init(int base, qemu_irq irq, CharDriverState *chr1,
+ CharDriverState *chr2)
{
int slavio_serial_io_memory, i;
SerialState *s;
@@ -565,8 +608,8 @@
s->chn[i].chn = 1 - i;
s->chn[i].type = ser;
if (s->chn[i].chr) {
- qemu_chr_add_read_handler(s->chn[i].chr, serial_can_receive, serial_receive1, &s->chn[i]);
- qemu_chr_add_event_handler(s->chn[i].chr, serial_event);
+ qemu_chr_add_handlers(s->chn[i].chr, serial_can_receive,
+ serial_receive1, serial_event, &s->chn[i]);
}
}
s->chn[0].otherchn = &s->chn[1];
@@ -603,12 +646,15 @@
KBD_DPRINTF("Command %d\n", val);
switch (val) {
case 1: // Reset, return type code
+ clear_queue(s);
put_queue(s, 0xff);
- put_queue(s, 5); // Type 5
+ put_queue(s, 4); // Type 4
break;
case 7: // Query layout
+ case 0xf:
+ clear_queue(s);
put_queue(s, 0xfe);
- put_queue(s, 0x20); // XXX, layout?
+ put_queue(s, 19); // XXX, layout?
break;
default:
break;
@@ -621,9 +667,6 @@
ChannelState *s = opaque;
int ch;
- /* XXX: SDL sometimes generates nul events: we delete them */
- if (dx == 0 && dy == 0 && dz == 0 && buttons_state == 0)
- return;
MS_DPRINTF("dx=%d dy=%d buttons=%01x\n", dx, dy, buttons_state);
ch = 0x80 | 0x7; /* protocol start byte, no buttons pressed */
@@ -661,7 +704,7 @@
put_queue(s, 0);
}
-void slavio_serial_ms_kbd_init(int base, int irq)
+void slavio_serial_ms_kbd_init(int base, qemu_irq irq)
{
int slavio_serial_io_memory, i;
SerialState *s;
@@ -684,6 +727,7 @@
qemu_add_mouse_event_handler(sunmouse_event, &s->chn[0], 0, "QEMU Sun Mouse");
qemu_add_kbd_event_handler(sunkbd_event, &s->chn[1]);
+ register_savevm("slavio_serial_mouse", base, 2, slavio_serial_save, slavio_serial_load, s);
qemu_register_reset(slavio_serial_reset, s);
slavio_serial_reset(s);
}
Modified: trunk/src/host/qemu-neo1973/hw/slavio_timer.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/slavio_timer.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/slavio_timer.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -57,6 +57,7 @@
int reached, stopped;
int mode; // 0 = processor, 1 = user, 2 = system
unsigned int cpu;
+ void *intctl;
} SLAVIO_TIMERState;
#define TIMER_MAXADDR 0x1f
@@ -103,7 +104,7 @@
DPRINTF("irq %d limit %d reached %d d %" PRId64 " count %d s->c %x diff %" PRId64 " stopped %d mode %d\n", s->irq, limit, s->reached?1:0, (ticks-s->count_load_time), count, s->count, s->expire_time - ticks, s->stopped, s->mode);
if (s->mode != 1)
- pic_set_irq_cpu(s->irq, out, s->cpu);
+ pic_set_irq_cpu(s->intctl, s->irq, out, s->cpu);
}
// timer callback
@@ -130,8 +131,7 @@
// part of counter (user mode)
if (s->mode != 1) {
// clear irq
- pic_set_irq_cpu(s->irq, 0, s->cpu);
- s->count_load_time = qemu_get_clock(vm_clock);
+ pic_set_irq_cpu(s->intctl, s->irq, 0, s->cpu);
s->reached = 0;
return s->limit;
}
@@ -266,7 +266,8 @@
slavio_timer_get_out(s);
}
-void slavio_timer_init(uint32_t addr, int irq, int mode, unsigned int cpu)
+void slavio_timer_init(uint32_t addr, int irq, int mode, unsigned int cpu,
+ void *intctl)
{
int slavio_timer_io_memory;
SLAVIO_TIMERState *s;
@@ -278,6 +279,7 @@
s->mode = mode;
s->cpu = cpu;
s->irq_timer = qemu_new_timer(vm_clock, slavio_timer_irq, s);
+ s->intctl = intctl;
slavio_timer_io_memory = cpu_register_io_memory(0, slavio_timer_mem_read,
slavio_timer_mem_write, s);
Added: trunk/src/host/qemu-neo1973/hw/smbus.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/smbus.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/smbus.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,309 @@
+/*
+ * QEMU SMBus device emulation.
+ *
+ * Copyright (c) 2007 CodeSourcery.
+ * Written by Paul Brook
+ *
+ * This code is licenced under the LGPL.
+ */
+
+/* TODO: Implement PEC. */
+
+#include "vl.h"
+
+#define DEBUG_SMBUS 1
+
+#ifdef DEBUG_SMBUS
+#define DPRINTF(fmt, args...) \
+do { printf("smbus(%02x): " fmt , dev->i2c.address, ##args); } while (0)
+#define BADF(fmt, args...) \
+do { fprintf(stderr, "smbus: error: " fmt , ##args); exit(1);} while (0)
+#else
+#define DPRINTF(fmt, args...) do {} while(0)
+#define BADF(fmt, args...) \
+do { fprintf(stderr, "smbus: error: " fmt , ##args);} while (0)
+#endif
+
+enum {
+ SMBUS_IDLE,
+ SMBUS_WRITE_DATA,
+ SMBUS_RECV_BYTE,
+ SMBUS_READ_DATA,
+ SMBUS_DONE,
+ SMBUS_CONFUSED = -1
+};
+
+static void smbus_do_quick_cmd(SMBusDevice *dev, int recv)
+{
+ DPRINTF("Quick Command %d\n", recv);
+ if (dev->quick_cmd)
+ dev->quick_cmd(dev, recv);
+}
+
+static void smbus_do_write(SMBusDevice *dev)
+{
+ uint8_t *p;
+ int len;
+
+ if (dev->data_len == 0) {
+ smbus_do_quick_cmd(dev, 0);
+ } else if (dev->data_len == 1) {
+ DPRINTF("Send Byte\n");
+ if (dev->send_byte) {
+ dev->send_byte(dev, dev->data_buf[0]);
+ }
+ } else {
+ dev->command = dev->data_buf[0];
+ DPRINTF("Command %d len %d\n", dev->command, dev->data_len - 1);
+ if (dev->write_data) {
+ dev->write_data(dev, dev->command, dev->data_buf + 1,
+ dev->data_len - 1);
+ }
+ }
+}
+
+void smbus_i2c_event(i2c_slave *s, enum i2c_event event)
+{
+ SMBusDevice *dev = (SMBusDevice *)s;
+ switch (event) {
+ case I2C_START_SEND:
+ switch (dev->mode) {
+ case SMBUS_IDLE:
+ DPRINTF("Incoming data\n");
+ dev->mode = SMBUS_WRITE_DATA;
+ break;
+ default:
+ BADF("Unexpected send start condition in state %d\n", dev->mode);
+ dev->mode = SMBUS_CONFUSED;
+ break;
+ }
+ break;
+
+ case I2C_START_RECV:
+ switch (dev->mode) {
+ case SMBUS_IDLE:
+ DPRINTF("Read mode\n");
+ dev->mode = SMBUS_RECV_BYTE;
+ break;
+ case SMBUS_WRITE_DATA:
+ if (dev->data_len == 0) {
+ BADF("Read after write with no data\n");
+ dev->mode = SMBUS_CONFUSED;
+ } else {
+ if (dev->data_len > 1) {
+ smbus_do_write(dev);
+ } else {
+ dev->command = dev->data_buf[0];
+ DPRINTF("%02x: Command %d\n", dev->i2c.address,
+ dev->command);
+ }
+ DPRINTF("Read mode\n");
+ dev->data_len = 0;
+ dev->mode = SMBUS_READ_DATA;
+ }
+ break;
+ default:
+ BADF("Unexpected recv start condition in state %d\n", dev->mode);
+ dev->mode = SMBUS_CONFUSED;
+ break;
+ }
+ break;
+
+ case I2C_FINISH:
+ switch (dev->mode) {
+ case SMBUS_WRITE_DATA:
+ smbus_do_write(dev);
+ break;
+ case SMBUS_RECV_BYTE:
+ smbus_do_quick_cmd(dev, 1);
+ break;
+ case SMBUS_READ_DATA:
+ BADF("Unexpected stop during receive\n");
+ break;
+ default:
+ /* Nothing to do. */
+ break;
+ }
+ dev->mode = SMBUS_IDLE;
+ dev->data_len = 0;
+ break;
+
+ case I2C_NACK:
+ switch (dev->mode) {
+ case SMBUS_DONE:
+ /* Nothing to do. */
+ break;
+ case SMBUS_READ_DATA:
+ dev->mode = SMBUS_DONE;
+ break;
+ default:
+ BADF("Unexpected NACK in state %d\n", dev->mode);
+ dev->mode = SMBUS_CONFUSED;
+ break;
+ }
+ }
+}
+
+static int smbus_i2c_recv(i2c_slave *s)
+{
+ SMBusDevice *dev = (SMBusDevice *)s;
+ int ret;
+
+ switch (dev->mode) {
+ case SMBUS_RECV_BYTE:
+ if (dev->receive_byte) {
+ ret = dev->receive_byte(dev);
+ } else {
+ ret = 0;
+ }
+ DPRINTF("Receive Byte %02x\n", ret);
+ dev->mode = SMBUS_DONE;
+ break;
+ case SMBUS_READ_DATA:
+ if (dev->read_data) {
+ ret = dev->read_data(dev, dev->command, dev->data_len);
+ dev->data_len++;
+ } else {
+ ret = 0;
+ }
+ DPRINTF("Read data %02x\n", ret);
+ break;
+ default:
+ BADF("Unexpected read in state %d\n", dev->mode);
+ dev->mode = SMBUS_CONFUSED;
+ ret = 0;
+ break;
+ }
+ return ret;
+}
+
+static int smbus_i2c_send(i2c_slave *s, uint8_t data)
+{
+ SMBusDevice *dev = (SMBusDevice *)s;
+ switch (dev->mode) {
+ case SMBUS_WRITE_DATA:
+ DPRINTF("Write data %02x\n", data);
+ dev->data_buf[dev->data_len++] = data;
+ break;
+ default:
+ BADF("Unexpected write in state %d\n", dev->mode);
+ break;
+ }
+ return 0;
+}
+
+SMBusDevice *smbus_device_init(i2c_bus *bus, int address, int size)
+{
+ SMBusDevice *dev;
+
+ if (size < sizeof(SMBusDevice))
+ cpu_abort(cpu_single_env, "SMBus struct too small");
+
+ dev = (SMBusDevice *)i2c_slave_init(bus, address, size);
+ dev->i2c.event = smbus_i2c_event;
+ dev->i2c.recv = smbus_i2c_recv;
+ dev->i2c.send = smbus_i2c_send;
+
+ return dev;
+}
+
+/* Master device commands. */
+void smbus_quick_command(i2c_bus *bus, int addr, int read)
+{
+ i2c_start_transfer(bus, addr, read);
+ i2c_end_transfer(bus);
+}
+
+uint8_t smbus_receive_byte(i2c_bus *bus, int addr)
+{
+ uint8_t data;
+
+ i2c_start_transfer(bus, addr, 1);
+ data = i2c_recv(bus);
+ i2c_nack(bus);
+ i2c_end_transfer(bus);
+ return data;
+}
+
+void smbus_send_byte(i2c_bus *bus, int addr, uint8_t data)
+{
+ i2c_start_transfer(bus, addr, 0);
+ i2c_send(bus, data);
+ i2c_end_transfer(bus);
+}
+
+uint8_t smbus_read_byte(i2c_bus *bus, int addr, uint8_t command)
+{
+ uint8_t data;
+ i2c_start_transfer(bus, addr, 0);
+ i2c_send(bus, command);
+ i2c_start_transfer(bus, addr, 1);
+ data = i2c_recv(bus);
+ i2c_nack(bus);
+ i2c_end_transfer(bus);
+ return data;
+}
+
+void smbus_write_byte(i2c_bus *bus, int addr, uint8_t command, uint8_t data)
+{
+ i2c_start_transfer(bus, addr, 0);
+ i2c_send(bus, command);
+ i2c_send(bus, data);
+ i2c_end_transfer(bus);
+}
+
+uint16_t smbus_read_word(i2c_bus *bus, int addr, uint8_t command)
+{
+ uint16_t data;
+ i2c_start_transfer(bus, addr, 0);
+ i2c_send(bus, command);
+ i2c_start_transfer(bus, addr, 1);
+ data = i2c_recv(bus);
+ data |= i2c_recv(bus) << 8;
+ i2c_nack(bus);
+ i2c_end_transfer(bus);
+ return data;
+}
+
+void smbus_write_word(i2c_bus *bus, int addr, uint8_t command, uint16_t data)
+{
+ i2c_start_transfer(bus, addr, 0);
+ i2c_send(bus, command);
+ i2c_send(bus, data & 0xff);
+ i2c_send(bus, data >> 8);
+ i2c_end_transfer(bus);
+}
+
+int smbus_read_block(i2c_bus *bus, int addr, uint8_t command, uint8_t *data)
+{
+ int len;
+ int i;
+
+ i2c_start_transfer(bus, addr, 0);
+ i2c_send(bus, command);
+ i2c_start_transfer(bus, addr, 1);
+ len = i2c_recv(bus);
+ if (len > 32)
+ len = 0;
+ for (i = 0; i < len; i++)
+ data[i] = i2c_recv(bus);
+ i2c_nack(bus);
+ i2c_end_transfer(bus);
+ return len;
+}
+
+void smbus_write_block(i2c_bus *bus, int addr, uint8_t command, uint8_t *data,
+ int len)
+{
+ int i;
+
+ if (len > 32)
+ len = 32;
+
+ i2c_start_transfer(bus, addr, 0);
+ i2c_send(bus, command);
+ i2c_send(bus, len);
+ for (i = 0; i < len; i++)
+ i2c_send(bus, data[i]);
+ i2c_end_transfer(bus);
+}
Added: trunk/src/host/qemu-neo1973/hw/smbus.h
===================================================================
--- trunk/src/host/qemu-neo1973/hw/smbus.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/smbus.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,70 @@
+/*
+ * QEMU SMBus API
+ *
+ * Copyright (c) 2007 Arastra, Inc.
+ *
+ * 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.
+ */
+
+typedef struct SMBusDevice SMBusDevice;
+
+struct SMBusDevice {
+ /* The SMBus protocol is implemented on top of I2C. */
+ i2c_slave i2c;
+
+ /* Callbacks set by the device. */
+ void (*quick_cmd)(SMBusDevice *dev, uint8_t read);
+ void (*send_byte)(SMBusDevice *dev, uint8_t val);
+ uint8_t (*receive_byte)(SMBusDevice *dev);
+ /* We can't distinguish between a word write and a block write with
+ length 1, so pass the whole data block including the length byte
+ (if present). The device is responsible figuring out what type of
+ command this is. */
+ void (*write_data)(SMBusDevice *dev, uint8_t cmd, uint8_t *buf, int len);
+ /* Likewise we can't distinguish between different reads, or even know
+ the length of the read until the read is complete, so read data a
+ byte at a time. The device is responsible for adding the length
+ byte on block reads. */
+ uint8_t (*read_data)(SMBusDevice *dev, uint8_t cmd, int n);
+
+ /* Remaining fields for internal use only. */
+ int mode;
+ int data_len;
+ uint8_t data_buf[34]; /* command + len + 32 bytes of data. */
+ uint8_t command;
+};
+
+/* Create a slave device. */
+SMBusDevice *smbus_device_init(i2c_bus *bus, int address, int size);
+
+/* Master device commands. */
+void smbus_quick_command(i2c_bus *bus, int addr, int read);
+uint8_t smbus_receive_byte(i2c_bus *bus, int addr);
+void smbus_send_byte(i2c_bus *bus, int addr, uint8_t data);
+uint8_t smbus_read_byte(i2c_bus *bus, int addr, uint8_t command);
+void smbus_write_byte(i2c_bus *bus, int addr, uint8_t command, uint8_t data);
+uint16_t smbus_read_word(i2c_bus *bus, int addr, uint8_t command);
+void smbus_write_word(i2c_bus *bus, int addr, uint8_t command, uint16_t data);
+int smbus_read_block(i2c_bus *bus, int addr, uint8_t command, uint8_t *data);
+void smbus_write_block(i2c_bus *bus, int addr, uint8_t command, uint8_t *data,
+ int len);
+
+/* smbus_eeprom.c */
+void smbus_eeprom_device_init(i2c_bus *bus, uint8_t addr, uint8_t *buf);
+
Added: trunk/src/host/qemu-neo1973/hw/smbus_eeprom.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/smbus_eeprom.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/smbus_eeprom.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,108 @@
+/*
+ * QEMU SMBus EEPROM device
+ *
+ * Copyright (c) 2007 Arastra, Inc.
+ *
+ * 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 "vl.h"
+
+//#define DEBUG
+
+typedef struct SMBusEEPROMDevice {
+ SMBusDevice dev;
+ uint8_t *data;
+ uint8_t offset;
+} SMBusEEPROMDevice;
+
+static void eeprom_quick_cmd(SMBusDevice *dev, uint8_t read)
+{
+#ifdef DEBUG
+ printf("eeprom_quick_cmd: addr=0x%02x read=%d\n", dev->addr, read);
+#endif
+}
+
+static void eeprom_send_byte(SMBusDevice *dev, uint8_t val)
+{
+ SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *) dev;
+#ifdef DEBUG
+ printf("eeprom_send_byte: addr=0x%02x val=0x%02x\n", dev->addr, val);
+#endif
+ eeprom->offset = val;
+}
+
+static uint8_t eeprom_receive_byte(SMBusDevice *dev)
+{
+ SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *) dev;
+ uint8_t val = eeprom->data[eeprom->offset++];
+#ifdef DEBUG
+ printf("eeprom_receive_byte: addr=0x%02x val=0x%02x\n", dev->addr, val);
+#endif
+ return val;
+}
+
+static void eeprom_write_data(SMBusDevice *dev, uint8_t cmd, uint8_t *buf, int len)
+{
+ SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *) dev;
+ int n;
+#ifdef DEBUG
+ printf("eeprom_write_byte: addr=0x%02x cmd=0x%02x val=0x%02x\n", dev->addr,
+ cmd, buf[0]);
+#endif
+ /* An page write operation is not a valid SMBus command.
+ It is a block write without a length byte. Fortunately we
+ get the full block anyway. */
+ /* TODO: Should this set the current location? */
+ if (cmd + len > 256)
+ n = 256 - cmd;
+ else
+ n = len;
+ memcpy(eeprom->data + cmd, buf, n);
+ len -= n;
+ if (len)
+ memcpy(eeprom->data, buf + n, len);
+}
+
+static uint8_t eeprom_read_data(SMBusDevice *dev, uint8_t cmd, int n)
+{
+ SMBusEEPROMDevice *eeprom = (SMBusEEPROMDevice *) dev;
+ /* If this is the first byte then set the current position. */
+ if (n == 0)
+ eeprom->offset = cmd;
+ /* As with writes, we implement block reads without the
+ SMBus length byte. */
+ return eeprom_receive_byte(dev);
+}
+
+void smbus_eeprom_device_init(i2c_bus *bus, uint8_t addr, uint8_t *buf)
+{
+ SMBusEEPROMDevice *eeprom;
+
+ eeprom = (SMBusEEPROMDevice *)smbus_device_init(bus, addr,
+ sizeof(SMBusEEPROMDevice));
+
+ eeprom->dev.quick_cmd = eeprom_quick_cmd;
+ eeprom->dev.send_byte = eeprom_send_byte;
+ eeprom->dev.receive_byte = eeprom_receive_byte;
+ eeprom->dev.write_data = eeprom_write_data;
+ eeprom->dev.read_data = eeprom_read_data;
+ eeprom->data = buf;
+ eeprom->offset = 0;
+}
Modified: trunk/src/host/qemu-neo1973/hw/smc91c111.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/smc91c111.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/smc91c111.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -24,8 +24,7 @@
uint16_t gpr;
uint16_t ptr;
uint16_t ercv;
- void *pic;
- int irq;
+ qemu_irq irq;
int bank;
int packet_num;
int tx_alloc;
@@ -86,7 +85,7 @@
if (s->tx_fifo_done_len != 0)
s->int_level |= INT_TX;
level = (s->int_level & s->int_mask) != 0;
- pic_set_irq_new(s->pic, s->irq, level);
+ qemu_set_irq(s->irq, level);
}
/* Try to allocate a packet. Returns 0x80 on failure. */
@@ -446,7 +445,9 @@
case 7:
/* Not implemented. */
return 0;
- case 8: /* Free memory available. */
+ case 8: /* Memory size. */
+ return NUM_PACKETS;
+ case 9: /* Free memory available. */
{
int i;
int n;
@@ -457,8 +458,6 @@
}
return n;
}
- case 9: /* Memory size. */
- return NUM_PACKETS;
case 10: case 11: /* RPCR */
/* Not implemented. */
return 0;
@@ -693,7 +692,7 @@
smc91c111_writel
};
-void smc91c111_init(NICInfo *nd, uint32_t base, void *pic, int irq)
+void smc91c111_init(NICInfo *nd, uint32_t base, qemu_irq irq)
{
smc91c111_state *s;
int iomemtype;
@@ -703,7 +702,6 @@
smc91c111_writefn, s);
cpu_register_physical_memory(base, 16, iomemtype);
s->base = base;
- s->pic = pic;
s->irq = irq;
memcpy(s->macaddr, nd->macaddr, 6);
Modified: trunk/src/host/qemu-neo1973/hw/sparc32_dma.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/sparc32_dma.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/sparc32_dma.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -37,9 +37,6 @@
#ifdef DEBUG_DMA
#define DPRINTF(fmt, args...) \
do { printf("DMA: " fmt , ##args); } while (0)
-#define pic_set_irq_new(ctl, irq, level) \
- do { printf("DMA: set_irq(%d): %d\n", (irq), (level)); \
- pic_set_irq_new((ctl), (irq),(level));} while (0)
#else
#define DPRINTF(fmt, args...)
#endif
@@ -58,17 +55,11 @@
struct DMAState {
uint32_t dmaregs[DMA_REGS];
- int espirq, leirq;
- void *iommu, *esp_opaque, *lance_opaque, *intctl;
+ qemu_irq espirq, leirq;
+ void *iommu, *esp_opaque, *lance_opaque;
+ qemu_irq *pic;
};
-void ledma_set_irq(void *opaque, int isr)
-{
- DMAState *s = opaque;
-
- pic_set_irq_new(s->intctl, s->leirq, isr);
-}
-
/* Note: on sparc, the lance 16 bit bus is swapped */
void ledma_memory_read(void *opaque, target_phys_addr_t addr,
uint8_t *buf, int len, int do_bswap)
@@ -125,8 +116,9 @@
{
DMAState *s = opaque;
+ DPRINTF("Raise ESP IRQ\n");
s->dmaregs[0] |= DMA_INTR;
- pic_set_irq_new(s->intctl, s->espirq, 1);
+ qemu_irq_raise(s->espirq);
}
void espdma_clear_irq(void *opaque)
@@ -134,7 +126,8 @@
DMAState *s = opaque;
s->dmaregs[0] &= ~DMA_INTR;
- pic_set_irq_new(s->intctl, s->espirq, 0);
+ DPRINTF("Lower ESP IRQ\n");
+ qemu_irq_lower(s->espirq);
}
void espdma_memory_read(void *opaque, uint8_t *buf, int len)
@@ -179,8 +172,10 @@
DPRINTF("write dmareg[%d]: 0x%8.8x -> 0x%8.8x\n", saddr, s->dmaregs[saddr], val);
switch (saddr) {
case 0:
- if (!(val & DMA_INTREN))
- pic_set_irq_new(s->intctl, s->espirq, 0);
+ if (!(val & DMA_INTREN)) {
+ DPRINTF("Lower ESP IRQ\n");
+ qemu_irq_lower(s->espirq);
+ }
if (val & DMA_RESET) {
esp_reset(s->esp_opaque);
} else if (val & 0x40) {
@@ -194,8 +189,12 @@
s->dmaregs[0] |= DMA_LOADED;
break;
case 4:
- if (!(val & DMA_INTREN))
- pic_set_irq_new(s->intctl, s->leirq, 0);
+ /* ??? Should this mask out the lance IRQ? The NIC may re-assert
+ this IRQ unexpectedly. */
+ if (!(val & DMA_INTREN)) {
+ DPRINTF("Lower Lance IRQ\n");
+ qemu_irq_lower(s->leirq);
+ }
if (val & DMA_RESET)
pcnet_h_reset(s->lance_opaque);
val &= 0x0fffffff;
@@ -250,7 +249,8 @@
return 0;
}
-void *sparc32_dma_init(uint32_t daddr, int espirq, int leirq, void *iommu, void *intctl)
+void *sparc32_dma_init(uint32_t daddr, qemu_irq espirq, qemu_irq leirq,
+ void *iommu)
{
DMAState *s;
int dma_io_memory;
@@ -262,7 +262,6 @@
s->espirq = espirq;
s->leirq = leirq;
s->iommu = iommu;
- s->intctl = intctl;
dma_io_memory = cpu_register_io_memory(0, dma_mem_read, dma_mem_write, s);
cpu_register_physical_memory(daddr, 16 * 2, dma_io_memory);
Modified: trunk/src/host/qemu-neo1973/hw/spitz.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/spitz.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/spitz.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -1,16 +1,18 @@
/*
- * Sharp Zaurus SL-C1000/C3000/C3100/C3200 platforms.
+ * PXA270-based Clamshell PDA platforms.
*
* Copyright (c) 2006 Openedhand Ltd.
* Written by Andrzej Zaborowski <balrog at zabor.org>
*
- * This code is licensed under the GPLv2.
+ * This code is licensed under the GNU GPL v2.
*/
#include "vl.h"
#define spitz_printf(format, ...) \
fprintf(stderr, "%s: " format, __FUNCTION__, ##__VA_ARGS__)
+#undef REG_FMT
+#define REG_FMT "0x%02lx"
/* Spitz Flash */
#define FLASH_BASE 0x0c000000
@@ -30,16 +32,16 @@
#define FLASHCTL_RYBY (1 << 5)
#define FLASHCTL_NCE (FLASHCTL_CE0 | FLASHCTL_CE1)
-struct sharpsl_nand_s {
+struct sl_nand_s {
target_phys_addr_t target_base;
struct nand_flash_s *nand;
uint8_t ctl;
struct ecc_state_s ecc;
};
-static uint32_t sharpsl_readb(void *opaque, target_phys_addr_t addr)
+static uint32_t sl_readb(void *opaque, target_phys_addr_t addr)
{
- struct sharpsl_nand_s *s = (struct sharpsl_nand_s *) opaque;
+ struct sl_nand_s *s = (struct sl_nand_s *) opaque;
int ryby;
addr -= s->target_base;
@@ -71,15 +73,15 @@
return ecc_digest(&s->ecc, nand_getio(s->nand));
default:
- spitz_printf("Bad register offset 0x%02lx\n", addr);
+ spitz_printf("Bad register offset " REG_FMT "\n", addr);
}
return 0;
}
-static void sharpsl_writeb(void *opaque, target_phys_addr_t addr,
+static void sl_writeb(void *opaque, target_phys_addr_t addr,
uint32_t value)
{
- struct sharpsl_nand_s *s = (struct sharpsl_nand_s *) opaque;
+ struct sl_nand_s *s = (struct sl_nand_s *) opaque;
addr -= s->target_base;
switch (addr) {
@@ -103,7 +105,7 @@
break;
default:
- spitz_printf("Bad register offset 0x%02lx\n", addr);
+ spitz_printf("Bad register offset " REG_FMT "\n", addr);
}
}
@@ -112,23 +114,22 @@
FLASH_1024M,
};
-static void sharpsl_flash_register(struct pxa2xx_state_s *cpu, int size)
+static void sl_flash_register(struct pxa2xx_state_s *cpu, int size)
{
int iomemtype;
- struct sharpsl_nand_s *s;
- CPUReadMemoryFunc *sharpsl_readfn[] = {
- sharpsl_readb,
- sharpsl_readb,
- sharpsl_readb,
+ struct sl_nand_s *s;
+ CPUReadMemoryFunc *sl_readfn[] = {
+ sl_readb,
+ sl_readb,
+ sl_readb,
};
- CPUWriteMemoryFunc *sharpsl_writefn[] = {
- sharpsl_writeb,
- sharpsl_writeb,
- sharpsl_writeb,
+ CPUWriteMemoryFunc *sl_writefn[] = {
+ sl_writeb,
+ sl_writeb,
+ sl_writeb,
};
- s = (struct sharpsl_nand_s *)
- qemu_mallocz(sizeof(struct sharpsl_nand_s));
+ s = (struct sl_nand_s *) qemu_mallocz(sizeof(struct sl_nand_s));
s->target_base = FLASH_BASE;
s->ctl = 0;
if (size == FLASH_128M)
@@ -136,8 +137,8 @@
else if (size == FLASH_1024M)
s->nand = nand_init(NAND_MFR_SAMSUNG, 0xf1);
- iomemtype = cpu_register_io_memory(0, sharpsl_readfn,
- sharpsl_writefn, s);
+ iomemtype = cpu_register_io_memory(0, sl_readfn,
+ sl_writefn, s);
cpu_register_physical_memory(s->target_base, 0x40, iomemtype);
}
@@ -302,7 +303,7 @@
QUEUE_KEY(0x2a | (~keycode & 0x80));
if ((code & FN ) && (s->modifiers & 2))
QUEUE_KEY(0x36 | (~keycode & 0x80));
-#endif
+#else
if (keycode & 0x80) {
if ((s->imodifiers & 1 ) && !(s->modifiers & 1))
QUEUE_KEY(0x2a | 0x80);
@@ -339,6 +340,7 @@
s->imodifiers |= 0x20;
}
}
+#endif
}
QUEUE_KEY((code & 0x7f) | (keycode & 0x80));
@@ -508,7 +510,7 @@
case SCOOP_GPRR:
return s->gprr;
default:
- spitz_printf("Bad register offset 0x%02lx\n", addr);
+ spitz_printf("Bad register offset " REG_FMT "\n", addr);
}
return 0;
@@ -556,7 +558,7 @@
s->gprr = value;
break;
default:
- spitz_printf("Bad register offset 0x%02lx\n", addr);
+ spitz_printf("Bad register offset " REG_FMT "\n", addr);
}
}
@@ -755,7 +757,7 @@
max111x_set_input(max1111, MAX1111_BATT_TEMP, 0);
}
-static void spitz_pendown_set(void *opaque, int level)
+static void spitz_pendown_set(void *opaque, int line, int level)
{
struct pxa2xx_state_s *cpu = (struct pxa2xx_state_s *) opaque;
pxa2xx_gpio_set(cpu->gpio, SPITZ_GPIO_TP_INT, level);
@@ -765,9 +767,9 @@
{
lcd_en = ads_en = max_en = 0;
- ads7846 = ads7846_init(spitz_pendown_set, cpu);
+ ads7846 = ads7846_init(qemu_allocate_irqs(spitz_pendown_set, cpu, 1)[0]);
- max1111 = max1111_init(0, cpu);
+ max1111 = max1111_init(0);
max111x_set_input(max1111, MAX1111_BATT_VOLT, SPITZ_BATTERY_VOLT);
max111x_set_input(max1111, MAX1111_BATT_TEMP, 0);
max111x_set_input(max1111, MAX1111_ACIN_VOLT, SPITZ_CHARGEON_ACIN);
@@ -802,30 +804,41 @@
/* Wm8750 and Max7310 on I2C */
#define AKITA_MAX_ADDR 0x18
-#define SPITZ_WM_ADDR 0x1b
+#define SPITZ_WM_ADDRL 0x1a
+#define SPITZ_WM_ADDRH 0x1b
-static void spitz_i2c_setup(struct pxa2xx_state_s *cpu)
-{
+#define SPITZ_GPIO_WM 5
+
#ifdef HAS_AUDIO
- AudioState *audio;
- struct i2c_slave_s *wm;
+static void spitz_wm8750_addr(int line, int level, void *opaque)
+{
+ i2c_slave *wm = (i2c_slave *) opaque;
+ if (level)
+ i2c_set_slave_address(wm, SPITZ_WM_ADDRH);
+ else
+ i2c_set_slave_address(wm, SPITZ_WM_ADDRL);
+}
#endif
- struct i2c_bus_s *bus = (struct i2c_bus_s *)
- qemu_mallocz(sizeof(struct i2c_bus_s));
+static void spitz_i2c_setup(struct pxa2xx_state_s *cpu)
+{
/* Attach the CPU on one end of our I2C bus. */
- i2c_master_attach(bus, &cpu->i2c[0]->master);
+ i2c_bus *bus = cpu->i2c[0]->bus;
#ifdef HAS_AUDIO
+ AudioState *audio;
+ i2c_slave *wm;
+
audio = AUD_init();
if (!audio)
return;
- wm = wm8750_init(audio);
-
/* Attach a WM8750 to the bus */
- i2c_slave_attach(bus, SPITZ_WM_ADDR, wm);
+ wm = wm8750_init(bus, audio);
+
+ spitz_wm8750_addr(0, 0, wm);
+ pxa2xx_gpio_handler_set(cpu->gpio, SPITZ_GPIO_WM, spitz_wm8750_addr, wm);
/* .. and to the sound interface. */
- cpu->i2s->opaque = wm->opaque;
+ cpu->i2s->opaque = wm;
cpu->i2s->codec_out = wm8750_dac_dat;
cpu->i2s->codec_in = wm8750_adc_dat;
wm8750_data_req_set(wm, cpu->i2s->data_req, cpu->i2s);
@@ -835,7 +848,7 @@
static void spitz_akita_i2c_setup(struct pxa2xx_state_s *cpu)
{
/* Attach a Max7310 to Akita I2C bus. */
- i2c_slave_attach(cpu->i2c[0]->master.bus, AKITA_MAX_ADDR, max7310_init());
+ i2c_set_slave_address(max7310_init(cpu->i2c[0]->bus), AKITA_MAX_ADDR);
}
/* Other peripherals */
@@ -929,8 +942,19 @@
pxa2xx_gpio_set(cpu->gpio, SPITZ_GPIO_SD_WP, wp);
}
+static void spitz_pcmcia_cb(void *opaque, int line, int level)
+{
+ struct pxa2xx_state_s *cpu = (struct pxa2xx_state_s *) opaque;
+ static const int gpio_map[] = {
+ SPITZ_GPIO_CF1_IRQ, SPITZ_GPIO_CF1_CD,
+ SPITZ_GPIO_CF2_IRQ, SPITZ_GPIO_CF2_CD,
+ };
+ pxa2xx_gpio_set(cpu->gpio, gpio_map[line], level);
+}
+
static void spitz_gpio_setup(struct pxa2xx_state_s *cpu, int slots)
{
+ qemu_irq *pcmcia_cb;
/*
* Bad hack: We toggle the LCD hsync GPIO on every GPIO status
* read to satisfy broken guests that poll-wait for hsync.
@@ -952,14 +976,11 @@
pxa2xx_gpio_handler_set(cpu->gpio, SPITZ_GPIO_ON_RESET, pxa2xx_reset, cpu);
/* PCMCIA signals: card's IRQ and Card-Detect */
+ pcmcia_cb = qemu_allocate_irqs(spitz_pcmcia_cb, cpu, slots * 2);
if (slots >= 1)
- pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[0],
- (void (*)(void *, int, int)) pxa2xx_gpio_set,
- SPITZ_GPIO_CF1_IRQ, SPITZ_GPIO_CF1_CD, cpu->gpio);
+ pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[0], pcmcia_cb[0], pcmcia_cb[1]);
if (slots >= 2)
- pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[1],
- (void (*)(void *, int, int)) pxa2xx_gpio_set,
- SPITZ_GPIO_CF2_IRQ, SPITZ_GPIO_CF2_CD, cpu->gpio);
+ pxa2xx_pcmcia_set_irq_cb(cpu->pcmcia[1], pcmcia_cb[2], pcmcia_cb[3]);
/* Initialise the screen rotation related signals */
spitz_gpio_invert[3] = 0; /* Always open */
@@ -976,7 +997,7 @@
#define MAGIC_CHG(a, b, c, d) ((d << 24) | (c << 16) | (b << 8) | a)
-struct __attribute__ ((__packed__)) sharpsl_param_info {
+struct __attribute__ ((__packed__)) sl_param_info {
uint32_t comadj_keyword;
int32_t comadj;
@@ -1007,227 +1028,130 @@
.phadadj = 0x01,
};
-static void sharpsl_bootparam_write(uint32_t ptr)
+static void sl_bootparam_write(uint32_t ptr)
{
memcpy(phys_ram_base + ptr, &spitz_bootparam,
- sizeof(struct sharpsl_param_info));
+ sizeof(struct sl_param_info));
}
-#define SHARPSL_PXA_PARAM_BASE 0xa0000a00
+#define SL_PXA_PARAM_BASE 0xa0000a00
/* Board init. */
+enum spitz_model_e { spitz, akita, borzoi, terrier };
-static void spitz_init(int ram_size, int vga_ram_size, int boot_device,
- DisplayState *ds, const char **fd_filename, int snapshot,
- const char *kernel_filename, const char *kernel_cmdline,
- const char *initrd_filename)
+static void spitz_common_init(int ram_size, int vga_ram_size,
+ DisplayState *ds, const char *kernel_filename,
+ const char *kernel_cmdline, const char *initrd_filename,
+ const char *cpu_model, enum spitz_model_e model, int arm_id)
{
uint32_t spitz_ram = 0x04000000;
uint32_t spitz_rom = 0x00800000;
struct pxa2xx_state_s *cpu;
struct scoop_info_s *scp;
- cpu = pxa270_init(ds, 4);
+ if (!cpu_model)
+ cpu_model = (model == terrier) ? "pxa270-c5" : "pxa270-c0";
- /* Setup memory */
+ /* Setup CPU & memory */
if (ram_size < spitz_ram + spitz_rom) {
fprintf(stderr, "This platform requires %i bytes of memory\n",
spitz_ram + spitz_rom);
exit(1);
}
- cpu_register_physical_memory(PXA2XX_RAM_BASE, spitz_ram, IO_MEM_RAM);
+ cpu = pxa270_init(spitz_ram, ds, cpu_model);
- sharpsl_flash_register(cpu, FLASH_128M);
+ sl_flash_register(cpu, (model == spitz) ? FLASH_128M : FLASH_1024M);
- cpu_register_physical_memory(0, spitz_rom, spitz_ram | IO_MEM_ROM);
+ cpu_register_physical_memory(0, spitz_rom,
+ qemu_ram_alloc(spitz_rom) | IO_MEM_ROM);
/* Setup peripherals */
spitz_keyboard_register(cpu);
spitz_ssp_attach(cpu);
- scp = spitz_scoop_init(cpu, 2);
+ scp = spitz_scoop_init(cpu, (model == akita) ? 1 : 2);
- spitz_scoop_gpio_setup(cpu, scp, 2);
+ spitz_scoop_gpio_setup(cpu, scp, (model == akita) ? 1 : 2);
- spitz_gpio_setup(cpu, 2);
+ spitz_gpio_setup(cpu, (model == akita) ? 1 : 2);
spitz_i2c_setup(cpu);
- /* A 4.0 GB microdrive is permanently sitting in CF slot 0 */
- spitz_microdrive_attach(cpu);
+ if (model == akita)
+ spitz_akita_i2c_setup(cpu);
+ if (model == terrier)
+ /* A 6.0 GB microdrive is permanently sitting in CF slot 0. */
+ spitz_microdrive_attach(cpu);
+ else if (model != akita)
+ /* A 4.0 GB microdrive is permanently sitting in CF slot 0. */
+ spitz_microdrive_attach(cpu);
+
/* Setup initial (reset) machine state */
- cpu->env->regs[15] = PXA2XX_RAM_BASE;
+ cpu->env->regs[15] = PXA2XX_SDRAM_BASE;
- arm_load_kernel(ram_size, kernel_filename, kernel_cmdline,
- initrd_filename, 0x2c9, PXA2XX_RAM_BASE);
- sharpsl_bootparam_write(SHARPSL_PXA_PARAM_BASE - PXA2XX_RAM_BASE);
+ arm_load_kernel(cpu->env, spitz_ram, kernel_filename, kernel_cmdline,
+ initrd_filename, arm_id, PXA2XX_SDRAM_BASE);
+ sl_bootparam_write(SL_PXA_PARAM_BASE - PXA2XX_SDRAM_BASE);
}
-/* TODO: remember to update this when Spitz support is more complete */
-static void borzoi_init(int ram_size, int vga_ram_size, int boot_device,
+static void spitz_init(int ram_size, int vga_ram_size, int boot_device,
DisplayState *ds, const char **fd_filename, int snapshot,
const char *kernel_filename, const char *kernel_cmdline,
- const char *initrd_filename)
+ const char *initrd_filename, const char *cpu_model)
{
- uint32_t spitz_ram = 0x04000000;
- uint32_t spitz_rom = 0x00800000;
- struct pxa2xx_state_s *cpu;
- struct scoop_info_s *scp;
+ spitz_common_init(ram_size, vga_ram_size, ds, kernel_filename,
+ kernel_cmdline, initrd_filename, cpu_model, spitz, 0x2c9);
+}
- cpu = pxa270_init(ds, 4);
-
- /* Setup memory */
- if (ram_size < spitz_ram) {
- fprintf(stderr, "This platform requires %i bytes of memory\n",
- ram_size);
- exit(1);
- }
- cpu_register_physical_memory(PXA2XX_RAM_BASE, spitz_ram, IO_MEM_RAM);
-
- sharpsl_flash_register(cpu, FLASH_1024M);
-
- cpu_register_physical_memory(0, spitz_rom, spitz_ram | IO_MEM_ROM);
-
- /* Setup peripherals */
- spitz_keyboard_register(cpu);
-
- spitz_ssp_attach(cpu);
-
- scp = spitz_scoop_init(cpu, 2);
-
- spitz_scoop_gpio_setup(cpu, scp, 2);
-
- spitz_gpio_setup(cpu, 2);
-
- spitz_i2c_setup(cpu);
-
- /* A 4.0 GB microdrive is permanently sitting in CF slot 0 */
- spitz_microdrive_attach(cpu);
-
- /* Setup initial (reset) machine state */
- cpu->env->regs[15] = PXA2XX_RAM_BASE;
-
- arm_load_kernel(ram_size, kernel_filename, kernel_cmdline,
- initrd_filename, 0x33f, PXA2XX_RAM_BASE);
- sharpsl_bootparam_write(SHARPSL_PXA_PARAM_BASE - PXA2XX_RAM_BASE);
+static void borzoi_init(int ram_size, int vga_ram_size, int boot_device,
+ DisplayState *ds, const char **fd_filename, int snapshot,
+ const char *kernel_filename, const char *kernel_cmdline,
+ const char *initrd_filename, const char *cpu_model)
+{
+ spitz_common_init(ram_size, vga_ram_size, ds, kernel_filename,
+ kernel_cmdline, initrd_filename, cpu_model, borzoi, 0x33f);
}
static void akita_init(int ram_size, int vga_ram_size, int boot_device,
DisplayState *ds, const char **fd_filename, int snapshot,
const char *kernel_filename, const char *kernel_cmdline,
- const char *initrd_filename)
+ const char *initrd_filename, const char *cpu_model)
{
- uint32_t spitz_ram = 0x04000000;
- uint32_t spitz_rom = 0x00800000;
- struct pxa2xx_state_s *cpu;
- struct scoop_info_s *scp;
-
- cpu = pxa270_init(ds, 4);
-
- /* Setup memory */
- if (ram_size < spitz_ram) {
- fprintf(stderr, "This platform requires %i bytes of memory\n",
- ram_size);
- exit(1);
- }
- cpu_register_physical_memory(PXA2XX_RAM_BASE, spitz_ram, IO_MEM_RAM);
-
- sharpsl_flash_register(cpu, FLASH_1024M);
-
- cpu_register_physical_memory(0, spitz_rom, spitz_ram | IO_MEM_ROM);
-
- /* Setup peripherals */
- spitz_keyboard_register(cpu);
-
- spitz_ssp_attach(cpu);
-
- scp = spitz_scoop_init(cpu, 1);
-
- spitz_scoop_gpio_setup(cpu, scp, 1);
-
- spitz_gpio_setup(cpu, 1);
-
- spitz_i2c_setup(cpu);
- spitz_akita_i2c_setup(cpu);
-
- /* Setup initial (reset) machine state */
- cpu->env->regs[15] = PXA2XX_RAM_BASE;
-
- arm_load_kernel(ram_size, kernel_filename, kernel_cmdline,
- initrd_filename, 0x2e8, PXA2XX_RAM_BASE);
- sharpsl_bootparam_write(SHARPSL_PXA_PARAM_BASE - PXA2XX_RAM_BASE);
+ spitz_common_init(ram_size, vga_ram_size, ds, kernel_filename,
+ kernel_cmdline, initrd_filename, cpu_model, akita, 0x2e8);
}
static void terrier_init(int ram_size, int vga_ram_size, int boot_device,
DisplayState *ds, const char **fd_filename, int snapshot,
const char *kernel_filename, const char *kernel_cmdline,
- const char *initrd_filename)
+ const char *initrd_filename, const char *cpu_model)
{
- uint32_t spitz_ram = 0x04000000;
- uint32_t spitz_rom = 0x00800000;
- struct pxa2xx_state_s *cpu;
- struct scoop_info_s *scp;
-
- cpu = pxa270_init(ds, 7);
-
- /* Setup memory */
- if (ram_size < spitz_ram) {
- fprintf(stderr, "This platform requires %i bytes of memory\n",
- ram_size);
- exit(1);
- }
- cpu_register_physical_memory(PXA2XX_RAM_BASE, spitz_ram, IO_MEM_RAM);
-
- sharpsl_flash_register(cpu, FLASH_1024M);
-
- cpu_register_physical_memory(0, spitz_rom, spitz_ram | IO_MEM_ROM);
-
- /* Setup peripherals */
- spitz_keyboard_register(cpu);
-
- spitz_ssp_attach(cpu);
-
- scp = spitz_scoop_init(cpu, 2);
-
- spitz_scoop_gpio_setup(cpu, scp, 2);
-
- spitz_gpio_setup(cpu, 2);
-
- spitz_i2c_setup(cpu);
-
- /* A 6.0 GB microdrive is permanently sitting in CF slot 0 */
- spitz_microdrive_attach(cpu);
-
- /* Setup initial (reset) machine state */
- cpu->env->regs[15] = PXA2XX_RAM_BASE;
-
- arm_load_kernel(ram_size, kernel_filename, kernel_cmdline,
- initrd_filename, 0x33f, PXA2XX_RAM_BASE);
- sharpsl_bootparam_write(SHARPSL_PXA_PARAM_BASE - PXA2XX_RAM_BASE);
+ spitz_common_init(ram_size, vga_ram_size, ds, kernel_filename,
+ kernel_cmdline, initrd_filename, cpu_model, terrier, 0x33f);
}
-QEMUMachine zaurusakita_machine = {
+QEMUMachine akitapda_machine = {
"akita",
- "Sharp Zaurus SL-C1000 aka Akita (PXA270)",
+ "Akita PDA (PXA270)",
akita_init,
};
-QEMUMachine zaurusspitz_machine = {
+QEMUMachine spitzpda_machine = {
"spitz",
- "Sharp Zaurus SL-C3000 aka Spitz (PXA270)",
+ "Spitz PDA (PXA270)",
spitz_init,
};
-QEMUMachine zaurusborzoi_machine = {
+QEMUMachine borzoipda_machine = {
"borzoi",
- "Sharp Zaurus SL-C3100 aka Borzoi (PXA270)",
+ "Borzoi PDA (PXA270)",
borzoi_init,
};
-QEMUMachine zaurusterrier_machine = {
+QEMUMachine terrierpda_machine = {
"terrier",
- "Sharp Zaurus SL-C3200 aka Terrier (PXA270)",
+ "Terrier PDA (PXA270)",
terrier_init,
};
Modified: trunk/src/host/qemu-neo1973/hw/sun4m.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/sun4m.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/sun4m.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -23,43 +23,45 @@
*/
#include "vl.h"
+/*
+ * Sun4m architecture was used in the following machines:
+ *
+ * SPARCserver 6xxMP/xx
+ * SPARCclassic (SPARCclassic Server)(SPARCstation LC) (4/15), SPARCclassic X (4/10)
+ * SPARCstation LX/ZX (4/30)
+ * SPARCstation Voyager
+ * SPARCstation 10/xx, SPARCserver 10/xx
+ * SPARCstation 5, SPARCserver 5
+ * SPARCstation 20/xx, SPARCserver 20
+ * SPARCstation 4
+ *
+ * See for example: http://www.sunhelp.org/faq/sunref1.html
+ */
+
#define KERNEL_LOAD_ADDR 0x00004000
#define CMDLINE_ADDR 0x007ff000
#define INITRD_LOAD_ADDR 0x00800000
#define PROM_SIZE_MAX (256 * 1024)
#define PROM_ADDR 0xffd00000
#define PROM_FILENAME "openbios-sparc32"
-#define PHYS_JJ_EEPROM 0x71200000 /* m48t08 */
-#define PHYS_JJ_IDPROM_OFF 0x1FD8
-#define PHYS_JJ_EEPROM_SIZE 0x2000
-// IRQs are not PIL ones, but master interrupt controller register
-// bits
-#define PHYS_JJ_IOMMU 0x10000000 /* I/O MMU */
-#define PHYS_JJ_TCX_FB 0x50000000 /* TCX frame buffer */
-#define PHYS_JJ_SLAVIO 0x70000000 /* Slavio base */
-#define PHYS_JJ_DMA 0x78400000 /* DMA controller */
-#define PHYS_JJ_ESP 0x78800000 /* ESP SCSI */
-#define PHYS_JJ_ESP_IRQ 18
-#define PHYS_JJ_LE 0x78C00000 /* Lance ethernet */
-#define PHYS_JJ_LE_IRQ 16
-#define PHYS_JJ_CLOCK 0x71D00000 /* Per-CPU timer/counter, L14 */
-#define PHYS_JJ_CLOCK_IRQ 7
-#define PHYS_JJ_CLOCK1 0x71D10000 /* System timer/counter, L10 */
-#define PHYS_JJ_CLOCK1_IRQ 19
-#define PHYS_JJ_INTR0 0x71E00000 /* Per-CPU interrupt control registers */
-#define PHYS_JJ_INTR_G 0x71E10000 /* Master interrupt control registers */
-#define PHYS_JJ_MS_KBD 0x71000000 /* Mouse and keyboard */
-#define PHYS_JJ_MS_KBD_IRQ 14
-#define PHYS_JJ_SER 0x71100000 /* Serial */
-#define PHYS_JJ_SER_IRQ 15
-#define PHYS_JJ_FDC 0x71400000 /* Floppy */
-#define PHYS_JJ_FLOPPY_IRQ 22
-#define PHYS_JJ_ME_IRQ 30 /* Module error, power fail */
-#define PHYS_JJ_CS 0x6c000000 /* Crystal CS4231 */
-#define PHYS_JJ_CS_IRQ 5
#define MAX_CPUS 16
+struct hwdef {
+ target_ulong iommu_base, slavio_base;
+ target_ulong intctl_base, counter_base, nvram_base, ms_kb_base, serial_base;
+ target_ulong fd_base;
+ target_ulong dma_base, esp_base, le_base;
+ target_ulong tcx_base, cs_base;
+ long vram_size, nvram_size;
+ // IRQ numbers are not PIL ones, but master interrupt controller register
+ // bit numbers
+ int intctl_g_intr, esp_irq, le_irq, cpu_irq, clock_irq, clock1_irq;
+ int ser_irq, ms_kb_irq, fd_irq, me_irq, cs_irq;
+ int machine_id; // For NVRAM
+ uint32_t intbit_to_level[32];
+};
+
/* TSC handling */
uint64_t cpu_get_tsc()
@@ -115,6 +117,34 @@
m48t59_write(nvram, addr + max - 1, '\0');
}
+static uint32_t nvram_set_var (m48t59_t *nvram, uint32_t addr,
+ const unsigned char *str)
+{
+ uint32_t len;
+
+ len = strlen(str) + 1;
+ nvram_set_string(nvram, addr, str, len);
+
+ return addr + len;
+}
+
+static void nvram_finish_partition (m48t59_t *nvram, uint32_t start,
+ uint32_t end)
+{
+ unsigned int i, sum;
+
+ // Length divided by 16
+ m48t59_write(nvram, start + 2, ((end - start) >> 12) & 0xff);
+ m48t59_write(nvram, start + 3, ((end - start) >> 4) & 0xff);
+ // Checksum
+ sum = m48t59_read(nvram, start);
+ for (i = 0; i < 14; i++) {
+ sum += m48t59_read(nvram, start + 2 + i);
+ sum = (sum + ((sum & 0xff00) >> 8)) & 0xff;
+ }
+ m48t59_write(nvram, start + 1, sum & 0xff);
+}
+
static m48t59_t *nvram;
extern int nographic;
@@ -122,10 +152,12 @@
static void nvram_init(m48t59_t *nvram, uint8_t *macaddr, const char *cmdline,
int boot_device, uint32_t RAM_size,
uint32_t kernel_size,
- int width, int height, int depth)
+ int width, int height, int depth,
+ int machine_id)
{
unsigned char tmp = 0;
- int i, j;
+ unsigned int i, j;
+ uint32_t start, end;
// Try to match PPC NVRAM
nvram_set_string(nvram, 0x00, "QEMU_BIOS", 16);
@@ -148,10 +180,32 @@
nvram_set_word(nvram, 0x56, height);
nvram_set_word(nvram, 0x58, depth);
+ // OpenBIOS nvram variables
+ // Variable partition
+ start = 252;
+ m48t59_write(nvram, start, 0x70);
+ nvram_set_string(nvram, start + 4, "system", 12);
+
+ end = start + 16;
+ for (i = 0; i < nb_prom_envs; i++)
+ end = nvram_set_var(nvram, end, prom_envs[i]);
+
+ m48t59_write(nvram, end++ , 0);
+ end = start + ((end - start + 15) & ~15);
+ nvram_finish_partition(nvram, start, end);
+
+ // free partition
+ start = end;
+ m48t59_write(nvram, start, 0x7f);
+ nvram_set_string(nvram, start + 4, "free", 12);
+
+ end = 0x1fd0;
+ nvram_finish_partition(nvram, start, end);
+
// Sun4m specific use
- i = 0x1fd8;
+ start = i = 0x1fd8;
m48t59_write(nvram, i++, 0x01);
- m48t59_write(nvram, i++, 0x80); /* Sun4m OBP */
+ m48t59_write(nvram, i++, machine_id);
j = 0;
m48t59_write(nvram, i++, macaddr[j++]);
m48t59_write(nvram, i++, macaddr[j++]);
@@ -161,10 +215,10 @@
m48t59_write(nvram, i, macaddr[j]);
/* Calculate checksum */
- for (i = 0x1fd8; i < 0x1fe7; i++) {
- tmp ^= m48t59_read(nvram, i);
+ for (i = start; i < start + 15; i++) {
+ tmp ^= m48t59_read(nvram, i);
}
- m48t59_write(nvram, 0x1fe7, tmp);
+ m48t59_write(nvram, start + 15, tmp);
}
static void *slavio_intctl;
@@ -179,21 +233,6 @@
slavio_irq_info(slavio_intctl);
}
-void pic_set_irq(int irq, int level)
-{
- slavio_pic_set_irq(slavio_intctl, irq, level);
-}
-
-void pic_set_irq_new(void *opaque, int irq, int level)
-{
- pic_set_irq(irq, level);
-}
-
-void pic_set_irq_cpu(int irq, int level, unsigned int cpu)
-{
- slavio_pic_set_irq_cpu(slavio_intctl, irq, level, cpu);
-}
-
static void *slavio_misc;
void qemu_system_powerdown(void)
@@ -207,24 +246,25 @@
cpu_reset(env);
}
-/* Sun4m hardware initialisation */
-static void sun4m_init(int ram_size, int vga_ram_size, int boot_device,
- DisplayState *ds, const char **fd_filename, int snapshot,
- const char *kernel_filename, const char *kernel_cmdline,
- const char *initrd_filename)
+static void sun4m_hw_init(const struct hwdef *hwdef, int ram_size,
+ DisplayState *ds, const char *cpu_model)
+
{
CPUState *env, *envs[MAX_CPUS];
- char buf[1024];
- int ret, linux_boot;
unsigned int i;
- long vram_size = 0x100000, prom_offset, initrd_size, kernel_size;
void *iommu, *dma, *main_esp, *main_lance = NULL;
+ const sparc_def_t *def;
+ qemu_irq *slavio_irq;
- linux_boot = (kernel_filename != NULL);
-
/* init CPUs */
+ sparc_find_by_name(cpu_model, &def);
+ if (def == NULL) {
+ fprintf(stderr, "Unable to find Sparc CPU definition\n");
+ exit(1);
+ }
for(i = 0; i < smp_cpus; i++) {
env = cpu_init();
+ cpu_sparc_register(env, def);
envs[i] = env;
if (i != 0)
env->halted = 1;
@@ -234,45 +274,82 @@
/* allocate RAM */
cpu_register_physical_memory(0, ram_size, 0);
- iommu = iommu_init(PHYS_JJ_IOMMU);
- slavio_intctl = slavio_intctl_init(PHYS_JJ_INTR0, PHYS_JJ_INTR_G);
+ iommu = iommu_init(hwdef->iommu_base);
+ slavio_intctl = slavio_intctl_init(hwdef->intctl_base,
+ hwdef->intctl_base + 0x10000,
+ &hwdef->intbit_to_level[0],
+ &slavio_irq);
for(i = 0; i < smp_cpus; i++) {
slavio_intctl_set_cpu(slavio_intctl, i, envs[i]);
}
- dma = sparc32_dma_init(PHYS_JJ_DMA, PHYS_JJ_ESP_IRQ, PHYS_JJ_LE_IRQ, iommu, slavio_intctl);
+ dma = sparc32_dma_init(hwdef->dma_base, slavio_irq[hwdef->esp_irq],
+ slavio_irq[hwdef->le_irq], iommu);
- tcx_init(ds, PHYS_JJ_TCX_FB, phys_ram_base + ram_size, ram_size, vram_size, graphic_width, graphic_height);
+ if (graphic_depth != 8 && graphic_depth != 24) {
+ fprintf(stderr, "qemu: Unsupported depth: %d\n", graphic_depth);
+ exit (1);
+ }
+ tcx_init(ds, hwdef->tcx_base, phys_ram_base + ram_size, ram_size,
+ hwdef->vram_size, graphic_width, graphic_height, graphic_depth);
if (nd_table[0].vlan) {
if (nd_table[0].model == NULL
|| strcmp(nd_table[0].model, "lance") == 0) {
- main_lance = lance_init(&nd_table[0], PHYS_JJ_LE, dma);
+ main_lance = lance_init(&nd_table[0], hwdef->le_base, dma,
+ slavio_irq[hwdef->le_irq]);
} else {
fprintf(stderr, "qemu: Unsupported NIC: %s\n", nd_table[0].model);
exit (1);
}
}
- nvram = m48t59_init(0, PHYS_JJ_EEPROM, 0, PHYS_JJ_EEPROM_SIZE, 8);
+ nvram = m48t59_init(slavio_irq[0], hwdef->nvram_base, 0,
+ hwdef->nvram_size, 8);
for (i = 0; i < MAX_CPUS; i++) {
- slavio_timer_init(PHYS_JJ_CLOCK + i * TARGET_PAGE_SIZE, PHYS_JJ_CLOCK_IRQ, 0, i);
+ slavio_timer_init(hwdef->counter_base + i * TARGET_PAGE_SIZE,
+ hwdef->clock_irq, 0, i, slavio_intctl);
}
- slavio_timer_init(PHYS_JJ_CLOCK1, PHYS_JJ_CLOCK1_IRQ, 2, (unsigned int)-1);
- slavio_serial_ms_kbd_init(PHYS_JJ_MS_KBD, PHYS_JJ_MS_KBD_IRQ);
+ slavio_timer_init(hwdef->counter_base + 0x10000, hwdef->clock1_irq, 2,
+ (unsigned int)-1, slavio_intctl);
+ slavio_serial_ms_kbd_init(hwdef->ms_kb_base, slavio_irq[hwdef->ms_kb_irq]);
// Slavio TTYA (base+4, Linux ttyS0) is the first Qemu serial device
// Slavio TTYB (base+0, Linux ttyS1) is the second Qemu serial device
- slavio_serial_init(PHYS_JJ_SER, PHYS_JJ_SER_IRQ, serial_hds[1], serial_hds[0]);
- fdctrl_init(PHYS_JJ_FLOPPY_IRQ, 0, 1, PHYS_JJ_FDC, fd_table);
- main_esp = esp_init(bs_table, PHYS_JJ_ESP, dma);
- slavio_misc = slavio_misc_init(PHYS_JJ_SLAVIO, PHYS_JJ_ME_IRQ);
- cs_init(PHYS_JJ_CS, PHYS_JJ_CS_IRQ, slavio_intctl);
+ slavio_serial_init(hwdef->serial_base, slavio_irq[hwdef->ser_irq],
+ serial_hds[1], serial_hds[0]);
+ fdctrl_init(slavio_irq[hwdef->fd_irq], 0, 1, hwdef->fd_base, fd_table);
+ main_esp = esp_init(bs_table, hwdef->esp_base, dma);
+
+ for (i = 0; i < MAX_DISKS; i++) {
+ if (bs_table[i]) {
+ esp_scsi_attach(main_esp, bs_table[i], i);
+ }
+ }
+
+ slavio_misc = slavio_misc_init(hwdef->slavio_base,
+ slavio_irq[hwdef->me_irq]);
+ if (hwdef->cs_base != (target_ulong)-1)
+ cs_init(hwdef->cs_base, hwdef->cs_irq, slavio_intctl);
sparc32_dma_set_reset_data(dma, main_esp, main_lance);
+}
+static void sun4m_load_kernel(long vram_size, int ram_size, int boot_device,
+ const char *kernel_filename,
+ const char *kernel_cmdline,
+ const char *initrd_filename,
+ int machine_id)
+{
+ int ret, linux_boot;
+ char buf[1024];
+ unsigned int i;
+ long prom_offset, initrd_size, kernel_size;
+
+ linux_boot = (kernel_filename != NULL);
+
prom_offset = ram_size + vram_size;
cpu_register_physical_memory(PROM_ADDR,
(PROM_SIZE_MAX + TARGET_PAGE_SIZE - 1) & TARGET_PAGE_MASK,
prom_offset | IO_MEM_ROM);
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAME);
- ret = load_elf(buf, 0, NULL);
+ ret = load_elf(buf, 0, NULL, NULL, NULL);
if (ret < 0) {
fprintf(stderr, "qemu: could not load prom '%s'\n",
buf);
@@ -281,7 +358,7 @@
kernel_size = 0;
if (linux_boot) {
- kernel_size = load_elf(kernel_filename, -0xf0000000, NULL);
+ kernel_size = load_elf(kernel_filename, -0xf0000000, NULL, NULL, NULL);
if (kernel_size < 0)
kernel_size = load_aout(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR);
if (kernel_size < 0)
@@ -313,11 +390,124 @@
}
}
}
- nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline, boot_device, ram_size, kernel_size, graphic_width, graphic_height, graphic_depth);
+ nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr, kernel_cmdline,
+ boot_device, ram_size, kernel_size, graphic_width,
+ graphic_height, graphic_depth, machine_id);
}
-QEMUMachine sun4m_machine = {
- "sun4m",
- "Sun4m platform",
- sun4m_init,
+static const struct hwdef hwdefs[] = {
+ /* SS-5 */
+ {
+ .iommu_base = 0x10000000,
+ .tcx_base = 0x50000000,
+ .cs_base = 0x6c000000,
+ .slavio_base = 0x70000000,
+ .ms_kb_base = 0x71000000,
+ .serial_base = 0x71100000,
+ .nvram_base = 0x71200000,
+ .fd_base = 0x71400000,
+ .counter_base = 0x71d00000,
+ .intctl_base = 0x71e00000,
+ .dma_base = 0x78400000,
+ .esp_base = 0x78800000,
+ .le_base = 0x78c00000,
+ .vram_size = 0x00100000,
+ .nvram_size = 0x2000,
+ .esp_irq = 18,
+ .le_irq = 16,
+ .clock_irq = 7,
+ .clock1_irq = 19,
+ .ms_kb_irq = 14,
+ .ser_irq = 15,
+ .fd_irq = 22,
+ .me_irq = 30,
+ .cs_irq = 5,
+ .machine_id = 0x80,
+ .intbit_to_level = {
+ 2, 3, 5, 7, 9, 11, 0, 14, 3, 5, 7, 9, 11, 13, 12, 12,
+ 6, 0, 4, 10, 8, 0, 11, 0, 0, 0, 0, 0, 15, 0, 15, 0,
+ },
+ },
+ /* SS-10 */
+ {
+ .iommu_base = 0xe0000000, // XXX Actually at 0xfe0000000ULL (36 bits)
+ .tcx_base = 0x20000000, // 0xe20000000ULL,
+ .cs_base = -1,
+ .slavio_base = 0xf0000000, // 0xff0000000ULL,
+ .ms_kb_base = 0xf1000000, // 0xff1000000ULL,
+ .serial_base = 0xf1100000, // 0xff1100000ULL,
+ .nvram_base = 0xf1200000, // 0xff1200000ULL,
+ .fd_base = 0xf1700000, // 0xff1700000ULL,
+ .counter_base = 0xf1300000, // 0xff1300000ULL,
+ .intctl_base = 0xf1400000, // 0xff1400000ULL,
+ .dma_base = 0xf0400000, // 0xef0400000ULL,
+ .esp_base = 0xf0800000, // 0xef0800000ULL,
+ .le_base = 0xf0c00000, // 0xef0c00000ULL,
+ .vram_size = 0x00100000,
+ .nvram_size = 0x2000,
+ .esp_irq = 18,
+ .le_irq = 16,
+ .clock_irq = 7,
+ .clock1_irq = 19,
+ .ms_kb_irq = 14,
+ .ser_irq = 15,
+ .fd_irq = 22,
+ .me_irq = 30,
+ .cs_irq = -1,
+ .machine_id = 0x72,
+ .intbit_to_level = {
+ 2, 3, 5, 7, 9, 11, 0, 14, 3, 5, 7, 9, 11, 13, 12, 12,
+ 6, 0, 4, 10, 8, 0, 11, 0, 0, 0, 0, 0, 15, 0, 15, 0,
+ },
+ },
};
+
+static void sun4m_common_init(int ram_size, int boot_device, DisplayState *ds,
+ const char *kernel_filename, const char *kernel_cmdline,
+ const char *initrd_filename, const char *cpu_model,
+ unsigned int machine)
+{
+ sun4m_hw_init(&hwdefs[machine], ram_size, ds, cpu_model);
+
+ sun4m_load_kernel(hwdefs[machine].vram_size, ram_size, boot_device,
+ kernel_filename, kernel_cmdline, initrd_filename,
+ hwdefs[machine].machine_id);
+}
+
+/* SPARCstation 5 hardware initialisation */
+static void ss5_init(int ram_size, int vga_ram_size, int boot_device,
+ DisplayState *ds, const char **fd_filename, int snapshot,
+ const char *kernel_filename, const char *kernel_cmdline,
+ const char *initrd_filename, const char *cpu_model)
+{
+ if (cpu_model == NULL)
+ cpu_model = "Fujitsu MB86904";
+ sun4m_common_init(ram_size, boot_device, ds, kernel_filename,
+ kernel_cmdline, initrd_filename, cpu_model,
+ 0);
+}
+
+/* SPARCstation 10 hardware initialisation */
+static void ss10_init(int ram_size, int vga_ram_size, int boot_device,
+ DisplayState *ds, const char **fd_filename, int snapshot,
+ const char *kernel_filename, const char *kernel_cmdline,
+ const char *initrd_filename, const char *cpu_model)
+{
+ if (cpu_model == NULL)
+ cpu_model = "TI SuperSparc II";
+ sun4m_common_init(ram_size, boot_device, ds, kernel_filename,
+ kernel_cmdline, initrd_filename, cpu_model,
+ 1);
+}
+
+QEMUMachine ss5_machine = {
+ "SS-5",
+ "Sun4m platform, SPARCstation 5",
+ ss5_init,
+};
+
+QEMUMachine ss10_machine = {
+ "SS-10",
+ "Sun4m platform, SPARCstation 10",
+ ss10_init,
+};
Modified: trunk/src/host/qemu-neo1973/hw/sun4u.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/sun4u.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/sun4u.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -170,6 +170,34 @@
return crc;
}
+static uint32_t nvram_set_var (m48t59_t *nvram, uint32_t addr,
+ const unsigned char *str)
+{
+ uint32_t len;
+
+ len = strlen(str) + 1;
+ NVRAM_set_string(nvram, addr, str, len);
+
+ return addr + len;
+}
+
+static void nvram_finish_partition (m48t59_t *nvram, uint32_t start,
+ uint32_t end)
+{
+ unsigned int i, sum;
+
+ // Length divided by 16
+ m48t59_write(nvram, start + 2, ((end - start) >> 12) & 0xff);
+ m48t59_write(nvram, start + 3, ((end - start) >> 4) & 0xff);
+ // Checksum
+ sum = m48t59_read(nvram, start);
+ for (i = 0; i < 14; i++) {
+ sum += m48t59_read(nvram, start + 2 + i);
+ sum = (sum + ((sum & 0xff00) >> 8)) & 0xff;
+ }
+ m48t59_write(nvram, start + 1, sum & 0xff);
+}
+
extern int nographic;
int sun4u_NVRAM_set_params (m48t59_t *nvram, uint16_t NVRAM_size,
@@ -182,6 +210,8 @@
int width, int height, int depth)
{
uint16_t crc;
+ unsigned int i;
+ uint32_t start, end;
/* Set parameters for Open Hack'Ware BIOS */
NVRAM_set_string(nvram, 0x00, "QEMU_BIOS", 16);
@@ -212,6 +242,28 @@
crc = NVRAM_compute_crc(nvram, 0x00, 0xF8);
NVRAM_set_word(nvram, 0xFC, crc);
+ // OpenBIOS nvram variables
+ // Variable partition
+ start = 252;
+ m48t59_write(nvram, start, 0x70);
+ NVRAM_set_string(nvram, start + 4, "system", 12);
+
+ end = start + 16;
+ for (i = 0; i < nb_prom_envs; i++)
+ end = nvram_set_var(nvram, end, prom_envs[i]);
+
+ m48t59_write(nvram, end++ , 0);
+ end = start + ((end - start + 15) & ~15);
+ nvram_finish_partition(nvram, start, end);
+
+ // free partition
+ start = end;
+ m48t59_write(nvram, start, 0x7f);
+ NVRAM_set_string(nvram, start + 4, "free", 12);
+
+ end = 0x1fd0;
+ nvram_finish_partition(nvram, start, end);
+
return 0;
}
@@ -223,14 +275,6 @@
{
}
-void pic_set_irq(int irq, int level)
-{
-}
-
-void pic_set_irq_new(void *opaque, int irq, int level)
-{
-}
-
void qemu_system_powerdown(void)
{
}
@@ -257,7 +301,7 @@
static void sun4u_init(int ram_size, int vga_ram_size, int boot_device,
DisplayState *ds, const char **fd_filename, int snapshot,
const char *kernel_filename, const char *kernel_cmdline,
- const char *initrd_filename)
+ const char *initrd_filename, const char *cpu_model)
{
CPUState *env;
char buf[1024];
@@ -266,10 +310,20 @@
unsigned int i;
long prom_offset, initrd_size, kernel_size;
PCIBus *pci_bus;
+ const sparc_def_t *def;
linux_boot = (kernel_filename != NULL);
+ /* init CPUs */
+ if (cpu_model == NULL)
+ cpu_model = "TI UltraSparc II";
+ sparc_find_by_name(cpu_model, &def);
+ if (def == NULL) {
+ fprintf(stderr, "Unable to find Sparc CPU definition\n");
+ exit(1);
+ }
env = cpu_init();
+ cpu_sparc_register(env, def);
register_savevm("cpu", 0, 3, cpu_save, cpu_load, env);
qemu_register_reset(main_cpu_reset, env);
@@ -282,7 +336,7 @@
prom_offset | IO_MEM_ROM);
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAME);
- ret = load_elf(buf, 0, NULL);
+ ret = load_elf(buf, 0, NULL, NULL, NULL);
if (ret < 0) {
fprintf(stderr, "qemu: could not load prom '%s'\n",
buf);
@@ -293,7 +347,7 @@
initrd_size = 0;
if (linux_boot) {
/* XXX: put correct offset */
- kernel_size = load_elf(kernel_filename, 0, NULL);
+ kernel_size = load_elf(kernel_filename, 0, NULL, NULL, NULL);
if (kernel_size < 0)
kernel_size = load_aout(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR);
if (kernel_size < 0)
@@ -330,27 +384,27 @@
for(i = 0; i < MAX_SERIAL_PORTS; i++) {
if (serial_hds[i]) {
- serial_init(&pic_set_irq_new, NULL,
- serial_io[i], serial_irq[i], serial_hds[i]);
+ serial_init(serial_io[i], NULL/*serial_irq[i]*/, serial_hds[i]);
}
}
for(i = 0; i < MAX_PARALLEL_PORTS; i++) {
if (parallel_hds[i]) {
- parallel_init(parallel_io[i], parallel_irq[i], parallel_hds[i]);
+ parallel_init(parallel_io[i], NULL/*parallel_irq[i]*/, parallel_hds[i]);
}
}
for(i = 0; i < nb_nics; i++) {
if (!nd_table[i].model)
nd_table[i].model = "ne2k_pci";
- pci_nic_init(pci_bus, &nd_table[i]);
+ pci_nic_init(pci_bus, &nd_table[i], -1);
}
pci_cmd646_ide_init(pci_bus, bs_table, 1);
- kbd_init();
- floppy_controller = fdctrl_init(6, 2, 0, 0x3f0, fd_table);
- nvram = m48t59_init(8, 0, 0x0074, NVRAM_SIZE, 59);
+ /* FIXME: wire up interrupts. */
+ i8042_init(NULL/*1*/, NULL/*12*/, 0x60);
+ floppy_controller = fdctrl_init(NULL/*6*/, 2, 0, 0x3f0, fd_table);
+ nvram = m48t59_init(NULL/*8*/, 0, 0x0074, NVRAM_SIZE, 59);
sun4u_NVRAM_set_params(nvram, NVRAM_SIZE, "Sun4u", ram_size, boot_device,
KERNEL_LOAD_ADDR, kernel_size,
kernel_cmdline,
Modified: trunk/src/host/qemu-neo1973/hw/tcx.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/tcx.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/tcx.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -26,19 +26,24 @@
#define MAXX 1024
#define MAXY 768
#define TCX_DAC_NREGS 16
+#define TCX_THC_NREGS_8 0x081c
+#define TCX_THC_NREGS_24 0x1000
+#define TCX_TEC_NREGS 0x1000
typedef struct TCXState {
uint32_t addr;
DisplayState *ds;
uint8_t *vram;
- ram_addr_t vram_offset;
- uint16_t width, height;
+ uint32_t *vram24, *cplane;
+ ram_addr_t vram_offset, vram24_offset, cplane_offset;
+ uint16_t width, height, depth;
uint8_t r[256], g[256], b[256];
uint32_t palette[256];
uint8_t dac_index, dac_state;
} TCXState;
static void tcx_screen_dump(void *opaque, const char *filename);
+static void tcx24_screen_dump(void *opaque, const char *filename);
/* XXX: unify with vga draw line functions */
static inline unsigned int rgb_to_pixel8(unsigned int r, unsigned int g, unsigned b)
@@ -121,6 +126,57 @@
}
}
+static inline void tcx24_draw_line32(TCXState *s1, uint8_t *d,
+ const uint8_t *s, int width,
+ const uint32_t *cplane,
+ const uint32_t *s24)
+{
+ int x;
+ uint8_t val;
+ uint32_t *p = (uint32_t *)d;
+ uint32_t dval;
+
+ for(x = 0; x < width; x++, s++, s24++) {
+ if ((bswap32(*cplane++) & 0xff000000) == 0x03000000) { // 24-bit direct
+ dval = bswap32(*s24) & 0x00ffffff;
+ } else {
+ val = *s;
+ dval = s1->palette[val];
+ }
+ *p++ = dval;
+ }
+}
+
+static inline int check_dirty(TCXState *ts, ram_addr_t page, ram_addr_t page24,
+ ram_addr_t cpage)
+{
+ int ret;
+ unsigned int off;
+
+ ret = cpu_physical_memory_get_dirty(page, VGA_DIRTY_FLAG);
+ for (off = 0; off < TARGET_PAGE_SIZE * 4; off += TARGET_PAGE_SIZE) {
+ ret |= cpu_physical_memory_get_dirty(page24 + off, VGA_DIRTY_FLAG);
+ ret |= cpu_physical_memory_get_dirty(cpage + off, VGA_DIRTY_FLAG);
+ }
+ return ret;
+}
+
+static inline void reset_dirty(TCXState *ts, ram_addr_t page_min,
+ ram_addr_t page_max, ram_addr_t page24,
+ ram_addr_t cpage)
+{
+ cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE,
+ VGA_DIRTY_FLAG);
+ page_min -= ts->vram_offset;
+ page_max -= ts->vram_offset;
+ cpu_physical_memory_reset_dirty(page24 + page_min * 4,
+ page24 + page_max * 4 + TARGET_PAGE_SIZE,
+ VGA_DIRTY_FLAG);
+ cpu_physical_memory_reset_dirty(cpage + page_min * 4,
+ cpage + page_max * 4 + TARGET_PAGE_SIZE,
+ VGA_DIRTY_FLAG);
+}
+
/* Fixed line length 1024 allows us to do nice tricks not possible on
VGA... */
static void tcx_update_display(void *opaque)
@@ -201,6 +257,82 @@
}
}
+static void tcx24_update_display(void *opaque)
+{
+ TCXState *ts = opaque;
+ ram_addr_t page, page_min, page_max, cpage, page24;
+ int y, y_start, dd, ds;
+ uint8_t *d, *s;
+ uint32_t *cptr, *s24;
+
+ if (ts->ds->depth != 32)
+ return;
+ page = ts->vram_offset;
+ page24 = ts->vram24_offset;
+ cpage = ts->cplane_offset;
+ y_start = -1;
+ page_min = 0xffffffff;
+ page_max = 0;
+ d = ts->ds->data;
+ s = ts->vram;
+ s24 = ts->vram24;
+ cptr = ts->cplane;
+ dd = ts->ds->linesize;
+ ds = 1024;
+
+ for(y = 0; y < ts->height; y += 4, page += TARGET_PAGE_SIZE,
+ page24 += TARGET_PAGE_SIZE, cpage += TARGET_PAGE_SIZE) {
+ if (check_dirty(ts, page, page24, cpage)) {
+ if (y_start < 0)
+ y_start = y;
+ if (page < page_min)
+ page_min = page;
+ if (page > page_max)
+ page_max = page;
+ tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
+ d += dd;
+ s += ds;
+ cptr += ds;
+ s24 += ds;
+ tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
+ d += dd;
+ s += ds;
+ cptr += ds;
+ s24 += ds;
+ tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
+ d += dd;
+ s += ds;
+ cptr += ds;
+ s24 += ds;
+ tcx24_draw_line32(ts, d, s, ts->width, cptr, s24);
+ d += dd;
+ s += ds;
+ cptr += ds;
+ s24 += ds;
+ } else {
+ if (y_start >= 0) {
+ /* flush to display */
+ dpy_update(ts->ds, 0, y_start,
+ ts->width, y - y_start);
+ y_start = -1;
+ }
+ d += dd * 4;
+ s += ds * 4;
+ cptr += ds * 4;
+ s24 += ds * 4;
+ }
+ }
+ if (y_start >= 0) {
+ /* flush to display */
+ dpy_update(ts->ds, 0, y_start,
+ ts->width, y - y_start);
+ }
+ /* reset modified pages */
+ if (page_min <= page_max) {
+ reset_dirty(ts, page_min, page_max, page24, cpage);
+ }
+}
+
static void tcx_invalidate_display(void *opaque)
{
TCXState *s = opaque;
@@ -211,14 +343,29 @@
}
}
+static void tcx24_invalidate_display(void *opaque)
+{
+ TCXState *s = opaque;
+ int i;
+
+ tcx_invalidate_display(s);
+ for (i = 0; i < MAXX*MAXY * 4; i += TARGET_PAGE_SIZE) {
+ cpu_physical_memory_set_dirty(s->vram24_offset + i);
+ cpu_physical_memory_set_dirty(s->cplane_offset + i);
+ }
+}
+
static void tcx_save(QEMUFile *f, void *opaque)
{
TCXState *s = opaque;
qemu_put_be32s(f, (uint32_t *)&s->addr);
qemu_put_be32s(f, (uint32_t *)&s->vram);
+ qemu_put_be32s(f, (uint32_t *)&s->vram24);
+ qemu_put_be32s(f, (uint32_t *)&s->cplane);
qemu_put_be16s(f, (uint16_t *)&s->height);
qemu_put_be16s(f, (uint16_t *)&s->width);
+ qemu_put_be16s(f, (uint16_t *)&s->depth);
qemu_put_buffer(f, s->r, 256);
qemu_put_buffer(f, s->g, 256);
qemu_put_buffer(f, s->b, 256);
@@ -230,19 +377,24 @@
{
TCXState *s = opaque;
- if (version_id != 1)
+ if (version_id != 2)
return -EINVAL;
qemu_get_be32s(f, (uint32_t *)&s->addr);
qemu_get_be32s(f, (uint32_t *)&s->vram);
+ qemu_get_be32s(f, (uint32_t *)&s->vram24);
+ qemu_get_be32s(f, (uint32_t *)&s->cplane);
qemu_get_be16s(f, (uint16_t *)&s->height);
qemu_get_be16s(f, (uint16_t *)&s->width);
+ qemu_get_be16s(f, (uint16_t *)&s->depth);
qemu_get_buffer(f, s->r, 256);
qemu_get_buffer(f, s->g, 256);
qemu_get_buffer(f, s->b, 256);
qemu_get_8s(f, &s->dac_index);
qemu_get_8s(f, &s->dac_state);
update_palette_entries(s, 0, 256);
+ tcx_invalidate_display(s);
+
return 0;
}
@@ -257,8 +409,8 @@
s->r[255] = s->g[255] = s->b[255] = 255;
update_palette_entries(s, 0, 256);
memset(s->vram, 0, MAXX*MAXY);
- cpu_physical_memory_reset_dirty(s->vram_offset, s->vram_offset + MAXX*MAXY,
- VGA_DIRTY_FLAG);
+ cpu_physical_memory_reset_dirty(s->vram_offset, s->vram_offset +
+ MAXX * MAXY * (1 + 4 + 4), VGA_DIRTY_FLAG);
s->dac_index = 0;
s->dac_state = 0;
}
@@ -294,6 +446,7 @@
case 2:
s->b[s->dac_index] = val >> 24;
update_palette_entries(s, s->dac_index, s->dac_index + 1);
+ s->dac_index = (s->dac_index + 1) & 255; // Index autoincrement
default:
s->dac_state = 0;
break;
@@ -317,28 +470,85 @@
tcx_dac_writel,
};
+static uint32_t tcx_dummy_readl(void *opaque, target_phys_addr_t addr)
+{
+ return 0;
+}
+
+static void tcx_dummy_writel(void *opaque, target_phys_addr_t addr,
+ uint32_t val)
+{
+}
+
+static CPUReadMemoryFunc *tcx_dummy_read[3] = {
+ tcx_dummy_readl,
+ tcx_dummy_readl,
+ tcx_dummy_readl,
+};
+
+static CPUWriteMemoryFunc *tcx_dummy_write[3] = {
+ tcx_dummy_writel,
+ tcx_dummy_writel,
+ tcx_dummy_writel,
+};
+
void tcx_init(DisplayState *ds, uint32_t addr, uint8_t *vram_base,
- unsigned long vram_offset, int vram_size, int width, int height)
+ unsigned long vram_offset, int vram_size, int width, int height,
+ int depth)
{
TCXState *s;
- int io_memory;
+ int io_memory, dummy_memory;
+ int size;
s = qemu_mallocz(sizeof(TCXState));
if (!s)
return;
s->ds = ds;
s->addr = addr;
- s->vram = vram_base;
s->vram_offset = vram_offset;
s->width = width;
s->height = height;
+ s->depth = depth;
- cpu_register_physical_memory(addr + 0x800000, vram_size, vram_offset);
+ // 8-bit plane
+ s->vram = vram_base;
+ size = vram_size;
+ cpu_register_physical_memory(addr + 0x00800000, size, vram_offset);
+ vram_offset += size;
+ vram_base += size;
+
io_memory = cpu_register_io_memory(0, tcx_dac_read, tcx_dac_write, s);
- cpu_register_physical_memory(addr + 0x200000, TCX_DAC_NREGS, io_memory);
+ cpu_register_physical_memory(addr + 0x00200000, TCX_DAC_NREGS, io_memory);
- graphic_console_init(s->ds, tcx_update_display, tcx_invalidate_display,
- tcx_screen_dump, s);
+ dummy_memory = cpu_register_io_memory(0, tcx_dummy_read, tcx_dummy_write,
+ s);
+ cpu_register_physical_memory(addr + 0x00700000, TCX_TEC_NREGS,
+ dummy_memory);
+ if (depth == 24) {
+ // 24-bit plane
+ size = vram_size * 4;
+ s->vram24 = (uint32_t *)vram_base;
+ s->vram24_offset = vram_offset;
+ cpu_register_physical_memory(addr + 0x02000000, size, vram_offset);
+ vram_offset += size;
+ vram_base += size;
+
+ // Control plane
+ size = vram_size * 4;
+ s->cplane = (uint32_t *)vram_base;
+ s->cplane_offset = vram_offset;
+ cpu_register_physical_memory(addr + 0x0a000000, size, vram_offset);
+ cpu_register_physical_memory(addr + 0x00301000, TCX_THC_NREGS_24,
+ dummy_memory);
+ graphic_console_init(s->ds, tcx24_update_display,
+ tcx24_invalidate_display, tcx24_screen_dump, s);
+ } else {
+ cpu_register_physical_memory(addr + 0x00300000, TCX_THC_NREGS_8,
+ dummy_memory);
+ graphic_console_init(s->ds, tcx_update_display, tcx_invalidate_display,
+ tcx_screen_dump, s);
+ }
+
register_savevm("tcx", addr, 1, tcx_save, tcx_load, s);
qemu_register_reset(tcx_reset, s);
tcx_reset(s);
@@ -372,5 +582,38 @@
return;
}
+static void tcx24_screen_dump(void *opaque, const char *filename)
+{
+ TCXState *s = opaque;
+ FILE *f;
+ uint8_t *d, *d1, v;
+ uint32_t *s24, *cptr, dval;
+ int y, x;
-
+ f = fopen(filename, "wb");
+ if (!f)
+ return;
+ fprintf(f, "P6\n%d %d\n%d\n", s->width, s->height, 255);
+ d1 = s->vram;
+ s24 = s->vram24;
+ cptr = s->cplane;
+ for(y = 0; y < s->height; y++) {
+ d = d1;
+ for(x = 0; x < s->width; x++, d++, s24++) {
+ if ((*cptr++ & 0xff000000) == 0x03000000) { // 24-bit direct
+ dval = *s24 & 0x00ffffff;
+ fputc((dval >> 16) & 0xff, f);
+ fputc((dval >> 8) & 0xff, f);
+ fputc(dval & 0xff, f);
+ } else {
+ v = *d;
+ fputc(s->r[v], f);
+ fputc(s->g[v], f);
+ fputc(s->b[v], f);
+ }
+ }
+ d1 += MAXX;
+ }
+ fclose(f);
+ return;
+}
Modified: trunk/src/host/qemu-neo1973/hw/unin_pci.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/unin_pci.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/unin_pci.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -146,12 +146,12 @@
return (irq_num + (pci_dev->devfn >> 3)) & 3;
}
-static void pci_unin_set_irq(void *pic, int irq_num, int level)
+static void pci_unin_set_irq(qemu_irq *pic, int irq_num, int level)
{
- openpic_set_irq(pic, irq_num + 8, level);
+ qemu_set_irq(pic[irq_num + 8], level);
}
-PCIBus *pci_pmac_init(void *pic)
+PCIBus *pci_pmac_init(qemu_irq *pic)
{
UNINState *s;
PCIDevice *d;
Modified: trunk/src/host/qemu-neo1973/hw/usb-hid.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/usb-hid.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/usb-hid.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -46,7 +46,7 @@
static const uint8_t qemu_mouse_dev_descriptor[] = {
0x12, /* u8 bLength; */
0x01, /* u8 bDescriptorType; Device */
- 0x10, 0x00, /* u16 bcdUSB; v1.0 */
+ 0x00, 0x01, /* u16 bcdUSB; v1.0 */
0x00, /* u8 bDeviceClass; */
0x00, /* u8 bDeviceSubClass; */
@@ -170,7 +170,7 @@
0x81, /* u8 ep_bEndpointAddress; IN Endpoint 1 */
0x03, /* u8 ep_bmAttributes; Interrupt */
0x08, 0x00, /* u16 ep_wMaxPacketSize; */
- 0x03, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */
+ 0x0a, /* u8 ep_bInterval; (255ms -- usb 2.0 spec) */
};
static const uint8_t qemu_mouse_hid_report_descriptor[] = {
Modified: trunk/src/host/qemu-neo1973/hw/usb-msd.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/usb-msd.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/usb-msd.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -66,7 +66,7 @@
static const uint8_t qemu_msd_dev_descriptor[] = {
0x12, /* u8 bLength; */
0x01, /* u8 bDescriptorType; Device */
- 0x10, 0x00, /* u16 bcdUSB; v1.0 */
+ 0x00, 0x01, /* u16 bcdUSB; v1.0 */
0x00, /* u8 bDeviceClass; */
0x00, /* u8 bDeviceSubClass; */
Modified: trunk/src/host/qemu-neo1973/hw/usb-net.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/usb-net.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/usb-net.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -111,7 +111,7 @@
STRING_MANUFACTURER, /* u8 iManufacturer; */
STRING_PRODUCT, /* u8 iProduct; */
STRING_SERIALNUMBER, /* u8 iSerialNumber; */
- 0x01 /* u8 bNumConfigurations; */
+ 0x02 /* u8 bNumConfigurations; */
};
static const uint8_t qemu_net_rndis_config_descriptor[] = {
@@ -195,8 +195,8 @@
USB_DT_CONFIG, /* u8 bDescriptorType */
0x50, 0x00, /* le16 wTotalLength */
0x02, /* u8 bNumInterfaces */
- DEV_RNDIS_CONFIG_VALUE, /* u8 bConfigurationValue */
- STRING_RNDIS, /* u8 iConfiguration */
+ DEV_CONFIG_VALUE, /* u8 bConfigurationValue */
+ STRING_CDC, /* u8 iConfiguration */
0xc0, /* u8 bmAttributes */
0x32, /* u8 bMaxPower */
/* CDC Control Interface */
@@ -972,12 +972,12 @@
case USB_DT_CONFIG:
switch (value & 0xff) {
- case 1:
+ case 0:
ret = sizeof(qemu_net_rndis_config_descriptor);
memcpy(data, qemu_net_rndis_config_descriptor, ret);
break;
- case 0:
+ case 1:
ret = sizeof(qemu_net_cdc_config_descriptor);
memcpy(data, qemu_net_cdc_config_descriptor, ret);
break;
Modified: trunk/src/host/qemu-neo1973/hw/usb-ohci.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/usb-ohci.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/usb-ohci.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -53,12 +53,14 @@
uint32_t ctrl;
} OHCIPort;
-typedef void (*ohci_irq_service_t)(void *opaque, int irq, int level);
+enum ohci_type {
+ OHCI_TYPE_PCI,
+ OHCI_TYPE_MEMIO
+};
typedef struct {
- void *pic;
- int irq;
- ohci_irq_service_t set_irq;
+ qemu_irq irq;
+ enum ohci_type type;
target_phys_addr_t mem_base;
int mem;
int num_ports;
@@ -279,7 +281,7 @@
(ohci->intr_status & ohci->intr))
level = 1;
- ohci->set_irq(ohci->pic, ohci->irq, level);
+ qemu_set_irq(ohci->irq, level);
}
/* Set an interrupt */
@@ -1257,7 +1259,7 @@
};
static void usb_ohci_init(OHCIState *ohci, int num_ports, int devfn,
- void *pic, int irq, ohci_irq_service_t set_irq, const char *name)
+ qemu_irq irq, enum ohci_type type, const char *name)
{
int i;
@@ -1280,9 +1282,8 @@
ohci->mem = cpu_register_io_memory(0, ohci_readfn, ohci_writefn, ohci);
ohci->name = name;
- ohci->pic = pic;
ohci->irq = irq;
- ohci->set_irq = set_irq;
+ ohci->type = type;
ohci->num_ports = num_ports;
for (i = 0; i < num_ports; i++) {
@@ -1328,20 +1329,20 @@
ohci->pci_dev.config[0x0b] = 0xc;
ohci->pci_dev.config[0x3d] = 0x01; /* interrupt pin 1 */
- usb_ohci_init(&ohci->state, num_ports, devfn, &ohci->pci_dev,
- 0, (ohci_irq_service_t) pci_set_irq, ohci->pci_dev.name);
+ usb_ohci_init(&ohci->state, num_ports, devfn, ohci->pci_dev.irq[0],
+ OHCI_TYPE_PCI, ohci->pci_dev.name);
pci_register_io_region((struct PCIDevice *)ohci, 0, 256,
PCI_ADDRESS_SPACE_MEM, ohci_mapfunc);
}
void usb_ohci_init_memio(target_phys_addr_t base, int num_ports, int devfn,
- void *pic, int irq)
+ qemu_irq irq)
{
OHCIState *ohci = (OHCIState *)qemu_mallocz(sizeof(OHCIState));
- usb_ohci_init(ohci, num_ports, devfn, pic, irq,
- pic_set_irq_new, "OHCI USB");
+ usb_ohci_init(ohci, num_ports, devfn, irq,
+ OHCI_TYPE_MEMIO, "OHCI USB");
ohci->mem_base = base;
cpu_register_physical_memory(ohci->mem_base, 0xfff, ohci->mem);
Modified: trunk/src/host/qemu-neo1973/hw/usb-uhci.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/usb-uhci.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/usb-uhci.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -26,6 +26,8 @@
//#define DEBUG
//#define DEBUG_PACKET
+#define UHCI_CMD_FGR (1 << 4)
+#define UHCI_CMD_EGSM (1 << 3)
#define UHCI_CMD_GRESET (1 << 2)
#define UHCI_CMD_HCRESET (1 << 1)
#define UHCI_CMD_RS (1 << 0)
@@ -87,7 +89,7 @@
is to allow multiple pending requests. */
uint32_t async_qh;
USBPacket usb_packet;
- uint8_t usb_buf[1280];
+ uint8_t usb_buf[2048];
} UHCIState;
typedef struct UHCI_TD {
@@ -117,7 +119,7 @@
} else {
level = 0;
}
- pci_set_irq(&s->dev, 3, level);
+ qemu_set_irq(s->dev.irq[3], level);
}
static void uhci_reset(UHCIState *s)
@@ -327,6 +329,21 @@
return val;
}
+/* signal resume if controller suspended */
+static void uhci_resume (void *opaque)
+{
+ UHCIState *s = (UHCIState *)opaque;
+
+ if (!s)
+ return;
+
+ if (s->cmd & UHCI_CMD_EGSM) {
+ s->cmd |= UHCI_CMD_FGR;
+ s->status |= UHCI_STS_RD;
+ uhci_update_irq(s);
+ }
+}
+
static void uhci_attach(USBPort *port1, USBDevice *dev)
{
UHCIState *s = port1->opaque;
@@ -344,6 +361,9 @@
port->ctrl |= UHCI_PORT_LSDA;
else
port->ctrl &= ~UHCI_PORT_LSDA;
+
+ uhci_resume(s);
+
port->port.dev = dev;
/* send the attach message */
usb_send_msg(dev, USB_MSG_ATTACH);
@@ -358,6 +378,9 @@
port->ctrl &= ~UHCI_PORT_EN;
port->ctrl |= UHCI_PORT_ENC;
}
+
+ uhci_resume(s);
+
dev = port->port.dev;
if (dev) {
/* send the detach message */
Modified: trunk/src/host/qemu-neo1973/hw/usb.h
===================================================================
--- trunk/src/host/qemu-neo1973/hw/usb.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/usb.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -164,7 +164,7 @@
USBCallback *complete_cb;
void *complete_opaque;
USBCallback *cancel_cb;
- void * *cancel_opaque;
+ void *cancel_opaque;
};
/* Defer completion of a USB packet. The hadle_packet routine should then
@@ -209,7 +209,7 @@
/* usb-ohci.c */
void usb_ohci_init_pci(struct PCIBus *bus, int num_ports, int devfn);
void usb_ohci_init_memio(target_phys_addr_t base, int num_ports, int devfn,
- void *pic, int irq);
+ qemu_irq irq);
/* usb-linux.c */
USBDevice *usb_host_device_open(const char *devname);
@@ -225,6 +225,3 @@
/* usb-msd.c */
USBDevice *usb_msd_init(const char *filename);
-
-/* usb-net.c */
-USBDevice *usb_net_init(NICInfo *nd);
Modified: trunk/src/host/qemu-neo1973/hw/versatile_pci.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/versatile_pci.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/versatile_pci.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -84,12 +84,12 @@
return irq_num;
}
-static void pci_vpb_set_irq(void *pic, int irq_num, int level)
+static void pci_vpb_set_irq(qemu_irq *pic, int irq_num, int level)
{
- pic_set_irq_new(pic, pci_vpb_irq + irq_num, level);
+ qemu_set_irq(pic[pci_vpb_irq + irq_num], level);
}
-PCIBus *pci_vpb_init(void *pic, int irq, int realview)
+PCIBus *pci_vpb_init(qemu_irq *pic, int irq, int realview)
{
PCIBus *s;
PCIDevice *d;
Modified: trunk/src/host/qemu-neo1973/hw/versatilepb.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/versatilepb.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/versatilepb.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -1,7 +1,7 @@
/*
* ARM Versatile Platform/Application Baseboard System emulation.
*
- * Copyright (c) 2005-2006 CodeSourcery.
+ * Copyright (c) 2005-2007 CodeSourcery.
* Written by Paul Brook
*
* This code is licenced under the GPL.
@@ -14,12 +14,11 @@
typedef struct vpb_sic_state
{
- arm_pic_handler handler;
uint32_t base;
uint32_t level;
uint32_t mask;
uint32_t pic_enable;
- void *parent;
+ qemu_irq *parent;
int irq;
} vpb_sic_state;
@@ -28,7 +27,7 @@
uint32_t flags;
flags = s->level & s->mask;
- pic_set_irq_new(s->parent, s->irq, flags != 0);
+ qemu_set_irq(s->parent[s->irq], flags != 0);
}
static void vpb_sic_update_pic(vpb_sic_state *s)
@@ -40,7 +39,7 @@
mask = 1u << i;
if (!(s->pic_enable & mask))
continue;
- pic_set_irq_new(s->parent, i, (s->level & mask) != 0);
+ qemu_set_irq(s->parent[i], (s->level & mask) != 0);
}
}
@@ -52,7 +51,7 @@
else
s->level &= ~(1u << irq);
if (s->pic_enable & (1u << irq))
- pic_set_irq_new(s->parent, irq, level);
+ qemu_set_irq(s->parent[irq], level);
vpb_sic_update(s);
}
@@ -126,15 +125,16 @@
vpb_sic_write
};
-static vpb_sic_state *vpb_sic_init(uint32_t base, void *parent, int irq)
+static qemu_irq *vpb_sic_init(uint32_t base, qemu_irq *parent, int irq)
{
vpb_sic_state *s;
+ qemu_irq *qi;
int iomemtype;
s = (vpb_sic_state *)qemu_mallocz(sizeof(vpb_sic_state));
if (!s)
return NULL;
- s->handler = vpb_sic_set_irq;
+ qi = qemu_allocate_irqs(vpb_sic_set_irq, s, 32);
s->base = base;
s->parent = parent;
s->irq = irq;
@@ -142,7 +142,7 @@
vpb_sic_writefn, s);
cpu_register_physical_memory(base, 0x00000fff, iomemtype);
/* ??? Save/restore. */
- return s;
+ return qi;
}
/* Board init. */
@@ -154,11 +154,12 @@
static void versatile_init(int ram_size, int vga_ram_size, int boot_device,
DisplayState *ds, const char **fd_filename, int snapshot,
const char *kernel_filename, const char *kernel_cmdline,
- const char *initrd_filename, int board_id)
+ const char *initrd_filename, const char *cpu_model,
+ int board_id)
{
CPUState *env;
- void *pic;
- void *sic;
+ qemu_irq *pic;
+ qemu_irq *sic;
void *scsi_hba;
PCIBus *pci_bus;
NICInfo *nd;
@@ -166,17 +167,19 @@
int done_smc = 0;
env = cpu_init();
- cpu_arm_set_model(env, ARM_CPUID_ARM926);
+ if (!cpu_model)
+ cpu_model = "arm926";
+ cpu_arm_set_model(env, cpu_model);
/* ??? RAM shoud repeat to fill physical memory space. */
/* SDRAM at address zero. */
cpu_register_physical_memory(0, ram_size, IO_MEM_RAM);
arm_sysctl_init(0x10000000, 0x41007004);
pic = arm_pic_init_cpu(env);
- pic = pl190_init(0x10140000, pic, ARM_PIC_CPU_IRQ, ARM_PIC_CPU_FIQ);
+ pic = pl190_init(0x10140000, pic[0], pic[1]);
sic = vpb_sic_init(0x10003000, pic, 31);
- pl050_init(0x10006000, sic, 3, 0);
- pl050_init(0x10007000, sic, 4, 1);
+ pl050_init(0x10006000, sic[3], 0);
+ pl050_init(0x10007000, sic[4], 1);
pci_bus = pci_vpb_init(sic, 27, 0);
/* The Versatile PCI bridge does not provide access to PCI IO space,
@@ -186,9 +189,9 @@
if (!nd->model)
nd->model = done_smc ? "rtl8139" : "smc91c111";
if (strcmp(nd->model, "smc91c111") == 0) {
- smc91c111_init(nd, 0x10010000, sic, 25);
+ smc91c111_init(nd, 0x10010000, sic[25]);
} else {
- pci_nic_init(pci_bus, nd);
+ pci_nic_init(pci_bus, nd, -1);
}
}
if (usb_enabled) {
@@ -201,32 +204,38 @@
}
}
- pl011_init(0x101f1000, pic, 12, serial_hds[0]);
- pl011_init(0x101f2000, pic, 13, serial_hds[1]);
- pl011_init(0x101f3000, pic, 14, serial_hds[2]);
- pl011_init(0x10009000, sic, 6, serial_hds[3]);
+ pl011_init(0x101f1000, pic[12], serial_hds[0]);
+ pl011_init(0x101f2000, pic[13], serial_hds[1]);
+ pl011_init(0x101f3000, pic[14], serial_hds[2]);
+ pl011_init(0x10009000, sic[6], serial_hds[3]);
- pl080_init(0x10130000, pic, 17, 8);
- sp804_init(0x101e2000, pic, 4);
- sp804_init(0x101e3000, pic, 5);
+ pl080_init(0x10130000, pic[17], 8);
+ sp804_init(0x101e2000, pic[4]);
+ sp804_init(0x101e3000, pic[5]);
/* The versatile/PB actually has a modified Color LCD controller
that includes hardware cursor support from the PL111. */
- pl110_init(ds, 0x10120000, pic, 16, 1);
+ pl110_init(ds, 0x10120000, pic[16], 1);
+ pl181_init(0x10005000, sd_bdrv, sic[22], sic[1]);
+#if 0
+ /* Disabled because there's no way of specifying a block device. */
+ pl181_init(0x1000b000, NULL, sic, 23, 2);
+#endif
+
/* Memory map for Versatile/PB: */
/* 0x10000000 System registers. */
/* 0x10001000 PCI controller config registers. */
/* 0x10002000 Serial bus interface. */
/* 0x10003000 Secondary interrupt controller. */
/* 0x10004000 AACI (audio). */
- /* 0x10005000 MMCI0. */
+ /* 0x10005000 MMCI0. */
/* 0x10006000 KMI0 (keyboard). */
/* 0x10007000 KMI1 (mouse). */
/* 0x10008000 Character LCD Interface. */
/* 0x10009000 UART3. */
/* 0x1000a000 Smart card 1. */
- /* 0x1000b000 MMCI1. */
+ /* 0x1000b000 MMCI1. */
/* 0x10010000 Ethernet. */
/* 0x10020000 USB. */
/* 0x10100000 SSMC. */
@@ -250,30 +259,30 @@
/* 0x101f3000 UART2. */
/* 0x101f4000 SSPI. */
- arm_load_kernel(ram_size, kernel_filename, kernel_cmdline,
+ arm_load_kernel(env, ram_size, kernel_filename, kernel_cmdline,
initrd_filename, board_id, 0x0);
}
static void vpb_init(int ram_size, int vga_ram_size, int boot_device,
DisplayState *ds, const char **fd_filename, int snapshot,
const char *kernel_filename, const char *kernel_cmdline,
- const char *initrd_filename)
+ const char *initrd_filename, const char *cpu_model)
{
versatile_init(ram_size, vga_ram_size, boot_device,
ds, fd_filename, snapshot,
kernel_filename, kernel_cmdline,
- initrd_filename, 0x183);
+ initrd_filename, cpu_model, 0x183);
}
static void vab_init(int ram_size, int vga_ram_size, int boot_device,
DisplayState *ds, const char **fd_filename, int snapshot,
const char *kernel_filename, const char *kernel_cmdline,
- const char *initrd_filename)
+ const char *initrd_filename, const char *cpu_model)
{
versatile_init(ram_size, vga_ram_size, boot_device,
ds, fd_filename, snapshot,
kernel_filename, kernel_cmdline,
- initrd_filename, 0x25e);
+ initrd_filename, cpu_model, 0x25e);
}
QEMUMachine versatilepb_machine = {
Modified: trunk/src/host/qemu-neo1973/hw/vga.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/vga.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/vga.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -1788,12 +1788,13 @@
s->get_bpp = vga_get_bpp;
s->get_offsets = vga_get_offsets;
s->get_resolution = vga_get_resolution;
- graphic_console_init(s->ds, vga_update_display, vga_invalidate_display,
- vga_screen_dump, s);
+ s->update = vga_update_display;
+ s->invalidate = vga_invalidate_display;
+ s->screen_dump = vga_screen_dump;
}
/* used by both ISA and PCI */
-static void vga_init(VGAState *s)
+void vga_init(VGAState *s)
{
int vga_io_memory;
@@ -1844,6 +1845,81 @@
vga_io_memory);
}
+/* Memory mapped interface */
+static uint32_t vga_mm_readb (void *opaque, target_phys_addr_t addr)
+{
+ VGAState *s = opaque;
+
+ return vga_ioport_read(s, (addr - s->base_ctrl) >> s->it_shift) & 0xff;
+}
+
+static void vga_mm_writeb (void *opaque,
+ target_phys_addr_t addr, uint32_t value)
+{
+ VGAState *s = opaque;
+
+ vga_ioport_write(s, (addr - s->base_ctrl) >> s->it_shift, value & 0xff);
+}
+
+static uint32_t vga_mm_readw (void *opaque, target_phys_addr_t addr)
+{
+ VGAState *s = opaque;
+
+ return vga_ioport_read(s, (addr - s->base_ctrl) >> s->it_shift) & 0xffff;
+}
+
+static void vga_mm_writew (void *opaque,
+ target_phys_addr_t addr, uint32_t value)
+{
+ VGAState *s = opaque;
+
+ vga_ioport_write(s, (addr - s->base_ctrl) >> s->it_shift, value & 0xffff);
+}
+
+static uint32_t vga_mm_readl (void *opaque, target_phys_addr_t addr)
+{
+ VGAState *s = opaque;
+
+ return vga_ioport_read(s, (addr - s->base_ctrl) >> s->it_shift);
+}
+
+static void vga_mm_writel (void *opaque,
+ target_phys_addr_t addr, uint32_t value)
+{
+ VGAState *s = opaque;
+
+ vga_ioport_write(s, (addr - s->base_ctrl) >> s->it_shift, value);
+}
+
+static CPUReadMemoryFunc *vga_mm_read_ctrl[] = {
+ &vga_mm_readb,
+ &vga_mm_readw,
+ &vga_mm_readl,
+};
+
+static CPUWriteMemoryFunc *vga_mm_write_ctrl[] = {
+ &vga_mm_writeb,
+ &vga_mm_writew,
+ &vga_mm_writel,
+};
+
+static void vga_mm_init(VGAState *s, target_phys_addr_t vram_base,
+ target_phys_addr_t ctrl_base, int it_shift)
+{
+ int s_ioport_ctrl, vga_io_memory;
+
+ s->base_ctrl = ctrl_base;
+ s->it_shift = it_shift;
+ s_ioport_ctrl = cpu_register_io_memory(0, vga_mm_read_ctrl, vga_mm_write_ctrl, s);
+ vga_io_memory = cpu_register_io_memory(0, vga_mem_read, vga_mem_write, s);
+
+ register_savevm("vga", 0, 2, vga_save, vga_load, s);
+
+ cpu_register_physical_memory(ctrl_base, 0x100000, s_ioport_ctrl);
+ s->bank_offset = 0;
+ cpu_register_physical_memory(vram_base + 0x000a0000, 0x20000, vga_io_memory);
+}
+
int isa_vga_init(DisplayState *ds, uint8_t *vga_ram_base,
unsigned long vga_ram_offset, int vga_ram_size)
{
@@ -1856,6 +1932,8 @@
vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size);
vga_init(s);
+ graphic_console_init(s->ds, s->update, s->invalidate, s->screen_dump, s);
+
#ifdef CONFIG_BOCHS_VBE
/* XXX: use optimized standard vga accesses */
cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
@@ -1864,6 +1942,30 @@
return 0;
}
+int isa_vga_mm_init(DisplayState *ds, uint8_t *vga_ram_base,
+ unsigned long vga_ram_offset, int vga_ram_size,
+ target_phys_addr_t vram_base, target_phys_addr_t ctrl_base,
+ int it_shift)
+{
+ VGAState *s;
+
+ s = qemu_mallocz(sizeof(VGAState));
+ if (!s)
+ return -1;
+
+ vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size);
+ vga_mm_init(s, vram_base, ctrl_base, it_shift);
+
+ graphic_console_init(s->ds, s->update, s->invalidate, s->screen_dump, s);
+
+#ifdef CONFIG_BOCHS_VBE
+ /* XXX: use optimized standard vga accesses */
+ cpu_register_physical_memory(VBE_DISPI_LFB_PHYSICAL_ADDRESS,
+ vga_ram_size, vga_ram_offset);
+#endif
+ return 0;
+}
+
int pci_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base,
unsigned long vga_ram_offset, int vga_ram_size,
unsigned long vga_bios_offset, int vga_bios_size)
@@ -1881,6 +1983,9 @@
vga_common_init(s, ds, vga_ram_base, vga_ram_offset, vga_ram_size);
vga_init(s);
+
+ graphic_console_init(s->ds, s->update, s->invalidate, s->screen_dump, s);
+
s->pci_dev = &d->dev;
pci_conf = d->dev.config;
Modified: trunk/src/host/qemu-neo1973/hw/vga_int.h
===================================================================
--- trunk/src/host/qemu-neo1973/hw/vga_int.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/vga_int.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -85,6 +85,8 @@
unsigned int vram_size; \
unsigned long bios_offset; \
unsigned int bios_size; \
+ target_phys_addr_t base_ctrl; \
+ int it_shift; \
PCIDevice *pci_dev; \
uint32_t latch; \
uint8_t sr_index; \
@@ -134,6 +136,9 @@
uint32_t cursor_offset; \
unsigned int (*rgb_to_pixel)(unsigned int r, \
unsigned int g, unsigned b); \
+ vga_hw_update_ptr update; \
+ vga_hw_invalidate_ptr invalidate; \
+ vga_hw_screen_dump_ptr screen_dump; \
/* hardware mouse cursor support */ \
uint32_t invalidated_y_table[VGA_MAX_HEIGHT / 32]; \
void (*cursor_invalidate)(struct VGAState *s); \
@@ -157,6 +162,7 @@
void vga_common_init(VGAState *s, DisplayState *ds, uint8_t *vga_ram_base,
unsigned long vga_ram_offset, int vga_ram_size);
+void vga_init(VGAState *s);
uint32_t vga_mem_readb(void *opaque, target_phys_addr_t addr);
void vga_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val);
void vga_invalidate_scanlines(VGAState *s, int y1, int y2);
Added: trunk/src/host/qemu-neo1973/hw/vmmouse.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/vmmouse.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/vmmouse.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,300 @@
+/*
+ * QEMU VMMouse emulation
+ *
+ * Copyright (C) 2007 Anthony Liguori <anthony at codemonkey.ws>
+ *
+ * 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 "vl.h"
+
+/* debug only vmmouse */
+//#define DEBUG_VMMOUSE
+
+/* VMMouse Commands */
+#define VMMOUSE_GETVERSION 10
+#define VMMOUSE_DATA 39
+#define VMMOUSE_STATUS 40
+#define VMMOUSE_COMMAND 41
+
+#define VMMOUSE_READ_ID 0x45414552
+#define VMMOUSE_DISABLE 0x000000f5
+#define VMMOUSE_REQUEST_RELATIVE 0x4c455252
+#define VMMOUSE_REQUEST_ABSOLUTE 0x53424152
+
+#define VMMOUSE_QUEUE_SIZE 1024
+
+#define VMMOUSE_MAGIC 0x564D5868
+#define VMMOUSE_VERSION 0x3442554a
+
+#ifdef DEBUG_VMMOUSE
+#define DPRINTF(fmt, ...) printf(fmt, ## __VA_ARGS__)
+#else
+#define DPRINTF(fmt, ...) do { } while (0)
+#endif
+
+typedef struct _VMMouseState
+{
+ uint32_t queue[VMMOUSE_QUEUE_SIZE];
+ uint16_t nb_queue;
+ uint16_t status;
+ uint8_t absolute;
+ QEMUPutMouseEntry *entry;
+ void *ps2_mouse;
+} VMMouseState;
+
+static uint32_t vmmouse_get_version(VMMouseState *s, uint32_t *magic)
+{
+ DPRINTF("vmmouse_get_version(%x)\n", *magic);
+ *magic = VMMOUSE_MAGIC;
+ return VMMOUSE_VERSION;
+}
+
+static uint32_t vmmouse_get_status(VMMouseState *s)
+{
+ DPRINTF("vmmouse_get_status()\n");
+ return (s->status << 16) | s->nb_queue;
+}
+
+static void vmmouse_mouse_event(void *opaque, int x, int y, int dz, int buttons_state)
+{
+ VMMouseState *s = opaque;
+ int buttons = 0;
+
+ if (s->nb_queue > (VMMOUSE_QUEUE_SIZE - 4))
+ return;
+
+ DPRINTF("vmmouse_mouse_event(%d, %d, %d, %d)\n",
+ x, y, dz, buttons_state);
+
+ if ((buttons_state & MOUSE_EVENT_LBUTTON))
+ buttons |= 0x20;
+ if ((buttons_state & MOUSE_EVENT_RBUTTON))
+ buttons |= 0x10;
+ if ((buttons_state & MOUSE_EVENT_MBUTTON))
+ buttons |= 0x08;
+
+ if (s->absolute) {
+ x <<= 1;
+ y <<= 1;
+ }
+
+ s->queue[s->nb_queue++] = buttons;
+ s->queue[s->nb_queue++] = x;
+ s->queue[s->nb_queue++] = y;
+ s->queue[s->nb_queue++] = dz;
+
+ /* need to still generate PS2 events to notify driver to
+ read from queue */
+ ps2_mouse_fake_event(s->ps2_mouse);
+}
+
+static void vmmouse_update_handler(VMMouseState *s)
+{
+ if (s->entry) {
+ qemu_remove_mouse_event_handler(s->entry);
+ s->entry = NULL;
+ }
+ if (s->status == 0)
+ s->entry = qemu_add_mouse_event_handler(vmmouse_mouse_event,
+ s, s->absolute,
+ "vmmouse");
+}
+
+static void vmmouse_read_id(VMMouseState *s)
+{
+ DPRINTF("vmmouse_read_id()\n");
+
+ if (s->nb_queue == VMMOUSE_QUEUE_SIZE)
+ return;
+
+ s->queue[s->nb_queue++] = VMMOUSE_VERSION;
+ s->status = 0;
+ vmmouse_update_handler(s);
+}
+
+static void vmmouse_request_relative(VMMouseState *s)
+{
+ DPRINTF("vmmouse_request_relative()\n");
+ s->absolute = 0;
+ vmmouse_update_handler(s);
+}
+
+static void vmmouse_request_absolute(VMMouseState *s)
+{
+ DPRINTF("vmmouse_request_absolute()\n");
+ s->absolute = 1;
+ vmmouse_update_handler(s);
+}
+
+static void vmmouse_disable(VMMouseState *s)
+{
+ DPRINTF("vmmouse_disable()\n");
+ s->status = 0xffff;
+ vmmouse_update_handler(s);
+}
+
+static void vmmouse_data(VMMouseState *s, uint32_t *data, uint32_t size)
+{
+ int i;
+
+ DPRINTF("vmmouse_data(%d)\n", size);
+
+ if (size == 0 || size > 6 || size > s->nb_queue) {
+ printf("vmmouse: driver requested too much data %d\n", size);
+ s->status = 0xffff;
+ vmmouse_update_handler(s);
+ return;
+ }
+
+ for (i = 0; i < size; i++)
+ data[i] = s->queue[i];
+
+ s->nb_queue -= size;
+ if (s->nb_queue)
+ memmove(s->queue, &s->queue[size], sizeof(s->queue[0]) * s->nb_queue);
+}
+
+static void vmmouse_get_data(uint32_t *data)
+{
+ CPUState *env = cpu_single_env;
+
+ data[0] = env->regs[R_EAX]; data[1] = env->regs[R_EBX];
+ data[2] = env->regs[R_ECX]; data[3] = env->regs[R_EDX];
+ data[4] = env->regs[R_ESI]; data[5] = env->regs[R_EDI];
+
+ DPRINTF("get_data = {%x, %x, %x, %x, %x, %x}\n",
+ data[0], data[1], data[2], data[3], data[4], data[5]);
+}
+
+static void vmmouse_set_data(const uint32_t *data)
+{
+ CPUState *env = cpu_single_env;
+
+ DPRINTF("set_data = {%x, %x, %x, %x, %x, %x}\n",
+ data[0], data[1], data[2], data[3], data[4], data[5]);
+
+ env->regs[R_EAX] = data[0]; env->regs[R_EBX] = data[1];
+ env->regs[R_ECX] = data[2]; env->regs[R_EDX] = data[3];
+ env->regs[R_ESI] = data[4]; env->regs[R_EDI] = data[5];
+}
+
+static uint32_t vmmouse_ioport_read(void *opaque, uint32_t addr)
+{
+ VMMouseState *s = opaque;
+ uint32_t data[6];
+ uint16_t command;
+
+ vmmouse_get_data(data);
+ if (data[0] != VMMOUSE_MAGIC)
+ goto error;
+
+ command = data[2] & 0xFFFF;
+
+ switch (command) {
+ case VMMOUSE_GETVERSION:
+ data[0] = vmmouse_get_version(s, &data[1]);
+ break;
+ case VMMOUSE_STATUS:
+ data[0] = vmmouse_get_status(s);
+ break;
+ case VMMOUSE_COMMAND:
+ switch (data[1]) {
+ case VMMOUSE_DISABLE:
+ vmmouse_disable(s);
+ break;
+ case VMMOUSE_READ_ID:
+ vmmouse_read_id(s);
+ break;
+ case VMMOUSE_REQUEST_RELATIVE:
+ vmmouse_request_relative(s);
+ break;
+ case VMMOUSE_REQUEST_ABSOLUTE:
+ vmmouse_request_absolute(s);
+ break;
+ default:
+ printf("vmmouse: unknown command %x\n", data[1]);
+ break;
+ }
+ break;
+ case VMMOUSE_DATA:
+ vmmouse_data(s, data, data[1]);
+ break;
+ default:
+ printf("vmmouse: unknown command %x\n", command);
+ break;
+ }
+
+error:
+ vmmouse_set_data(data);
+ return data[0];
+}
+
+static void vmmouse_save(QEMUFile *f, void *opaque)
+{
+ VMMouseState *s = opaque;
+ int i;
+
+ qemu_put_be32(f, VMMOUSE_QUEUE_SIZE);
+ for (i = 0; i < VMMOUSE_QUEUE_SIZE; i++)
+ qemu_put_be32s(f, &s->queue[i]);
+ qemu_put_be16s(f, &s->nb_queue);
+ qemu_put_be16s(f, &s->status);
+ qemu_put_8s(f, &s->absolute);
+}
+
+static int vmmouse_load(QEMUFile *f, void *opaque, int version_id)
+{
+ VMMouseState *s = opaque;
+ int i;
+
+ if (version_id != 0)
+ return -EINVAL;
+
+ if (qemu_get_be32(f) != VMMOUSE_QUEUE_SIZE)
+ return -EINVAL;
+ for (i = 0; i < VMMOUSE_QUEUE_SIZE; i++)
+ qemu_get_be32s(f, &s->queue[i]);
+ qemu_get_be16s(f, &s->nb_queue);
+ qemu_get_be16s(f, &s->status);
+ qemu_get_8s(f, &s->absolute);
+
+ vmmouse_update_handler(s);
+
+ return 0;
+}
+
+void *vmmouse_init(void *m)
+{
+ VMMouseState *s = NULL;
+
+ DPRINTF("vmmouse_init\n");
+
+ s = qemu_mallocz(sizeof(VMMouseState));
+ if (!s)
+ return NULL;
+
+ s->status = 0xffff;
+ s->ps2_mouse = m;
+
+ register_ioport_read(0x5658, 1, 4, vmmouse_ioport_read, s);
+ register_savevm("vmmouse", 0, 0, vmmouse_save, vmmouse_load, s);
+
+ return s;
+}
+
Added: trunk/src/host/qemu-neo1973/hw/vmware_vga.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/vmware_vga.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/vmware_vga.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,1187 @@
+/*
+ * QEMU VMware-SVGA "chipset".
+ *
+ * Copyright (c) 2007 Andrzej Zaborowski <balrog at zabor.org>
+ *
+ * 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 "vl.h"
+
+#define VERBOSE
+#define EMBED_STDVGA
+#undef DIRECT_VRAM
+#define HW_RECT_ACCEL
+#define HW_FILL_ACCEL
+#define HW_MOUSE_ACCEL
+
+#ifdef EMBED_STDVGA
+# include "vga_int.h"
+#endif
+
+struct vmsvga_state_s {
+#ifdef EMBED_STDVGA
+ VGA_STATE_COMMON
+#endif
+
+ int width;
+ int height;
+ int invalidated;
+ int depth;
+ int bypp;
+ int enable;
+ int config;
+ struct {
+ int id;
+ int x;
+ int y;
+ int on;
+ } cursor;
+
+#ifndef EMBED_STDVGA
+ DisplayState *ds;
+ int vram_size;
+#endif
+ uint8_t *vram;
+
+ int index;
+ int scratch_size;
+ uint32_t *scratch;
+ int new_width;
+ int new_height;
+ uint32_t guest;
+ uint32_t svgaid;
+ uint32_t wred;
+ uint32_t wgreen;
+ uint32_t wblue;
+ int syncing;
+ int fb_size;
+
+ union {
+ uint32_t *fifo;
+ struct __attribute__((__packed__)) {
+ uint32_t min;
+ uint32_t max;
+ uint32_t next_cmd;
+ uint32_t stop;
+ /* Add registers here when adding capabilities. */
+ uint32_t fifo[0];
+ } *cmd;
+ };
+
+#define REDRAW_FIFO_LEN 512
+ struct vmsvga_rect_s {
+ int x, y, w, h;
+ } redraw_fifo[REDRAW_FIFO_LEN];
+ int redraw_fifo_first, redraw_fifo_last;
+};
+
+struct pci_vmsvga_state_s {
+ PCIDevice card;
+ struct vmsvga_state_s chip;
+};
+
+#define SVGA_MAGIC 0x900000UL
+#define SVGA_MAKE_ID(ver) (SVGA_MAGIC << 8 | (ver))
+#define SVGA_ID_0 SVGA_MAKE_ID(0)
+#define SVGA_ID_1 SVGA_MAKE_ID(1)
+#define SVGA_ID_2 SVGA_MAKE_ID(2)
+
+#define SVGA_LEGACY_BASE_PORT 0x4560
+#define SVGA_INDEX_PORT 0x0
+#define SVGA_VALUE_PORT 0x1
+#define SVGA_BIOS_PORT 0x2
+
+#define SVGA_VERSION_2
+
+#ifdef SVGA_VERSION_2
+# define SVGA_ID SVGA_ID_2
+# define SVGA_IO_BASE SVGA_LEGACY_BASE_PORT
+# define SVGA_IO_MUL 1
+# define SVGA_FIFO_SIZE 0x10000
+# define SVGA_MEM_BASE 0xe0000000
+# define SVGA_PCI_DEVICE_ID PCI_DEVICE_ID_VMWARE_SVGA2
+#else
+# define SVGA_ID SVGA_ID_1
+# define SVGA_IO_BASE SVGA_LEGACY_BASE_PORT
+# define SVGA_IO_MUL 4
+# define SVGA_FIFO_SIZE 0x10000
+# define SVGA_MEM_BASE 0xe0000000
+# define SVGA_PCI_DEVICE_ID PCI_DEVICE_ID_VMWARE_SVGA
+#endif
+
+enum {
+ /* ID 0, 1 and 2 registers */
+ SVGA_REG_ID = 0,
+ SVGA_REG_ENABLE = 1,
+ SVGA_REG_WIDTH = 2,
+ SVGA_REG_HEIGHT = 3,
+ SVGA_REG_MAX_WIDTH = 4,
+ SVGA_REG_MAX_HEIGHT = 5,
+ SVGA_REG_DEPTH = 6,
+ SVGA_REG_BITS_PER_PIXEL = 7, /* Current bpp in the guest */
+ SVGA_REG_PSEUDOCOLOR = 8,
+ SVGA_REG_RED_MASK = 9,
+ SVGA_REG_GREEN_MASK = 10,
+ SVGA_REG_BLUE_MASK = 11,
+ SVGA_REG_BYTES_PER_LINE = 12,
+ SVGA_REG_FB_START = 13,
+ SVGA_REG_FB_OFFSET = 14,
+ SVGA_REG_VRAM_SIZE = 15,
+ SVGA_REG_FB_SIZE = 16,
+
+ /* ID 1 and 2 registers */
+ SVGA_REG_CAPABILITIES = 17,
+ SVGA_REG_MEM_START = 18, /* Memory for command FIFO */
+ SVGA_REG_MEM_SIZE = 19,
+ SVGA_REG_CONFIG_DONE = 20, /* Set when memory area configured */
+ SVGA_REG_SYNC = 21, /* Write to force synchronization */
+ SVGA_REG_BUSY = 22, /* Read to check if sync is done */
+ SVGA_REG_GUEST_ID = 23, /* Set guest OS identifier */
+ SVGA_REG_CURSOR_ID = 24, /* ID of cursor */
+ SVGA_REG_CURSOR_X = 25, /* Set cursor X position */
+ SVGA_REG_CURSOR_Y = 26, /* Set cursor Y position */
+ SVGA_REG_CURSOR_ON = 27, /* Turn cursor on/off */
+ SVGA_REG_HOST_BITS_PER_PIXEL = 28, /* Current bpp in the host */
+ SVGA_REG_SCRATCH_SIZE = 29, /* Number of scratch registers */
+ SVGA_REG_MEM_REGS = 30, /* Number of FIFO registers */
+ SVGA_REG_NUM_DISPLAYS = 31, /* Number of guest displays */
+ SVGA_REG_PITCHLOCK = 32, /* Fixed pitch for all modes */
+
+ SVGA_PALETTE_BASE = 1024, /* Base of SVGA color map */
+ SVGA_PALETTE_END = SVGA_PALETTE_BASE + 767,
+ SVGA_SCRATCH_BASE = SVGA_PALETTE_BASE + 768,
+};
+
+#define SVGA_CAP_NONE 0
+#define SVGA_CAP_RECT_FILL (1 << 0)
+#define SVGA_CAP_RECT_COPY (1 << 1)
+#define SVGA_CAP_RECT_PAT_FILL (1 << 2)
+#define SVGA_CAP_LEGACY_OFFSCREEN (1 << 3)
+#define SVGA_CAP_RASTER_OP (1 << 4)
+#define SVGA_CAP_CURSOR (1 << 5)
+#define SVGA_CAP_CURSOR_BYPASS (1 << 6)
+#define SVGA_CAP_CURSOR_BYPASS_2 (1 << 7)
+#define SVGA_CAP_8BIT_EMULATION (1 << 8)
+#define SVGA_CAP_ALPHA_CURSOR (1 << 9)
+#define SVGA_CAP_GLYPH (1 << 10)
+#define SVGA_CAP_GLYPH_CLIPPING (1 << 11)
+#define SVGA_CAP_OFFSCREEN_1 (1 << 12)
+#define SVGA_CAP_ALPHA_BLEND (1 << 13)
+#define SVGA_CAP_3D (1 << 14)
+#define SVGA_CAP_EXTENDED_FIFO (1 << 15)
+#define SVGA_CAP_MULTIMON (1 << 16)
+#define SVGA_CAP_PITCHLOCK (1 << 17)
+
+/*
+ * FIFO offsets (seen as an array of 32-bit words)
+ */
+enum {
+ /*
+ * The original defined FIFO offsets
+ */
+ SVGA_FIFO_MIN = 0,
+ SVGA_FIFO_MAX, /* The distance from MIN to MAX must be at least 10K */
+ SVGA_FIFO_NEXT_CMD,
+ SVGA_FIFO_STOP,
+
+ /*
+ * Additional offsets added as of SVGA_CAP_EXTENDED_FIFO
+ */
+ SVGA_FIFO_CAPABILITIES = 4,
+ SVGA_FIFO_FLAGS,
+ SVGA_FIFO_FENCE,
+ SVGA_FIFO_3D_HWVERSION,
+ SVGA_FIFO_PITCHLOCK,
+};
+
+#define SVGA_FIFO_CAP_NONE 0
+#define SVGA_FIFO_CAP_FENCE (1 << 0)
+#define SVGA_FIFO_CAP_ACCELFRONT (1 << 1)
+#define SVGA_FIFO_CAP_PITCHLOCK (1 << 2)
+
+#define SVGA_FIFO_FLAG_NONE 0
+#define SVGA_FIFO_FLAG_ACCELFRONT (1 << 0)
+
+/* These values can probably be changed arbitrarily. */
+#define SVGA_SCRATCH_SIZE 0x8000
+#define SVGA_MAX_WIDTH 2360
+#define SVGA_MAX_HEIGHT 1770
+
+#ifdef VERBOSE
+# define GUEST_OS_BASE 0x5001
+static const char *vmsvga_guest_id[] = {
+ [0x0] = "Dos",
+ [0x1] = "Windows 3.1",
+ [0x2] = "Windows 95",
+ [0x3] = "Windows 98",
+ [0x4] = "Windows ME",
+ [0x5] = "Windows NT",
+ [0x6] = "Windows 2000",
+ [0x7] = "Linux",
+ [0x8] = "OS/2",
+ [0x9] = "Unknown",
+ [0xa] = "BSD",
+ [0xb] = "Whistler",
+};
+#endif
+
+enum {
+ SVGA_CMD_INVALID_CMD = 0,
+ SVGA_CMD_UPDATE = 1,
+ SVGA_CMD_RECT_FILL = 2,
+ SVGA_CMD_RECT_COPY = 3,
+ SVGA_CMD_DEFINE_BITMAP = 4,
+ SVGA_CMD_DEFINE_BITMAP_SCANLINE = 5,
+ SVGA_CMD_DEFINE_PIXMAP = 6,
+ SVGA_CMD_DEFINE_PIXMAP_SCANLINE = 7,
+ SVGA_CMD_RECT_BITMAP_FILL = 8,
+ SVGA_CMD_RECT_PIXMAP_FILL = 9,
+ SVGA_CMD_RECT_BITMAP_COPY = 10,
+ SVGA_CMD_RECT_PIXMAP_COPY = 11,
+ SVGA_CMD_FREE_OBJECT = 12,
+ SVGA_CMD_RECT_ROP_FILL = 13,
+ SVGA_CMD_RECT_ROP_COPY = 14,
+ SVGA_CMD_RECT_ROP_BITMAP_FILL = 15,
+ SVGA_CMD_RECT_ROP_PIXMAP_FILL = 16,
+ SVGA_CMD_RECT_ROP_BITMAP_COPY = 17,
+ SVGA_CMD_RECT_ROP_PIXMAP_COPY = 18,
+ SVGA_CMD_DEFINE_CURSOR = 19,
+ SVGA_CMD_DISPLAY_CURSOR = 20,
+ SVGA_CMD_MOVE_CURSOR = 21,
+ SVGA_CMD_DEFINE_ALPHA_CURSOR = 22,
+ SVGA_CMD_DRAW_GLYPH = 23,
+ SVGA_CMD_DRAW_GLYPH_CLIPPED = 24,
+ SVGA_CMD_UPDATE_VERBOSE = 25,
+ SVGA_CMD_SURFACE_FILL = 26,
+ SVGA_CMD_SURFACE_COPY = 27,
+ SVGA_CMD_SURFACE_ALPHA_BLEND = 28,
+ SVGA_CMD_FRONT_ROP_FILL = 29,
+ SVGA_CMD_FENCE = 30,
+};
+
+/* Legal values for the SVGA_REG_CURSOR_ON register in cursor bypass mode */
+enum {
+ SVGA_CURSOR_ON_HIDE = 0,
+ SVGA_CURSOR_ON_SHOW = 1,
+ SVGA_CURSOR_ON_REMOVE_FROM_FB = 2,
+ SVGA_CURSOR_ON_RESTORE_TO_FB = 3,
+};
+
+static inline void vmsvga_update_rect(struct vmsvga_state_s *s,
+ int x, int y, int w, int h)
+{
+#ifndef DIRECT_VRAM
+ int line = h;
+ int bypl = s->bypp * s->width;
+ int width = s->bypp * w;
+ int start = s->bypp * x + bypl * y;
+ uint8_t *src = s->vram + start;
+ uint8_t *dst = s->ds->data + start;
+
+ for (; line > 0; line --, src += bypl, dst += bypl)
+ memcpy(dst, src, width);
+#endif
+
+ dpy_update(s->ds, x, y, w, h);
+}
+
+static inline void vmsvga_update_screen(struct vmsvga_state_s *s)
+{
+#ifndef DIRECT_VRAM
+ memcpy(s->ds->data, s->vram, s->bypp * s->width * s->height);
+#endif
+
+ dpy_update(s->ds, 0, 0, s->width, s->height);
+}
+
+#ifdef DIRECT_VRAM
+# define vmsvga_update_rect_delayed vmsvga_update_rect
+#else
+static inline void vmsvga_update_rect_delayed(struct vmsvga_state_s *s,
+ int x, int y, int w, int h)
+{
+ struct vmsvga_rect_s *rect = &s->redraw_fifo[s->redraw_fifo_last ++];
+ s->redraw_fifo_last &= REDRAW_FIFO_LEN - 1;
+ rect->x = x;
+ rect->y = y;
+ rect->w = w;
+ rect->h = h;
+}
+#endif
+
+static inline void vmsvga_update_rect_flush(struct vmsvga_state_s *s)
+{
+ struct vmsvga_rect_s *rect;
+ if (s->invalidated) {
+ s->redraw_fifo_first = s->redraw_fifo_last;
+ return;
+ }
+ /* Overlapping region updates can be optimised out here - if someone
+ * knows a smart algorithm to do that, please share. */
+ while (s->redraw_fifo_first != s->redraw_fifo_last) {
+ rect = &s->redraw_fifo[s->redraw_fifo_first ++];
+ s->redraw_fifo_first &= REDRAW_FIFO_LEN - 1;
+ vmsvga_update_rect(s, rect->x, rect->y, rect->w, rect->h);
+ }
+}
+
+#ifdef HW_RECT_ACCEL
+static inline void vmsvga_copy_rect(struct vmsvga_state_s *s,
+ int x0, int y0, int x1, int y1, int w, int h)
+{
+# ifdef DIRECT_VRAM
+ uint8_t *vram = s->ds->data;
+# else
+ uint8_t *vram = s->vram;
+# endif
+ int bypl = s->bypp * s->width;
+ int width = s->bypp * w;
+ int line = h;
+ uint8_t *ptr[2];
+
+# ifdef DIRECT_VRAM
+ if (s->ds->dpy_copy)
+ s->ds->dpy_copy(s->ds, x0, y0, x1, y1, w, h);
+ else
+# endif
+ {
+ if (y1 > y0) {
+ ptr[0] = vram + s->bypp * x0 + bypl * (y0 + h - 1);
+ ptr[1] = vram + s->bypp * x1 + bypl * (y1 + h - 1);
+ for (; line > 0; line --, ptr[0] -= bypl, ptr[1] -= bypl)
+ memmove(ptr[1], ptr[0], width);
+ } else {
+ ptr[0] = vram + s->bypp * x0 + bypl * y0;
+ ptr[1] = vram + s->bypp * x1 + bypl * y1;
+ for (; line > 0; line --, ptr[0] += bypl, ptr[1] += bypl)
+ memmove(ptr[1], ptr[0], width);
+ }
+ }
+
+ vmsvga_update_rect_delayed(s, x1, y1, w, h);
+}
+#endif
+
+#ifdef HW_FILL_ACCEL
+static inline void vmsvga_fill_rect(struct vmsvga_state_s *s,
+ uint32_t c, int x, int y, int w, int h)
+{
+# ifdef DIRECT_VRAM
+ uint8_t *vram = s->ds->data;
+# else
+ uint8_t *vram = s->vram;
+# endif
+ int bypp = s->bypp;
+ int bypl = bypp * s->width;
+ int width = bypp * w;
+ int line = h;
+ int column;
+ uint8_t *fst = vram + bypp * x + bypl * y;
+ uint8_t *dst;
+ uint8_t *src;
+ uint8_t col[4];
+
+# ifdef DIRECT_VRAM
+ if (s->ds->dpy_fill)
+ s->ds->dpy_fill(s->ds, x, y, w, h, c);
+ else
+# endif
+ {
+ col[0] = c;
+ col[1] = c >> 8;
+ col[2] = c >> 16;
+ col[3] = c >> 24;
+
+ if (line --) {
+ dst = fst;
+ src = col;
+ for (column = width; column > 0; column --) {
+ *(dst ++) = *(src ++);
+ if (src - col == bypp)
+ src = col;
+ }
+ dst = fst;
+ for (; line > 0; line --) {
+ dst += bypl;
+ memcpy(dst, fst, width);
+ }
+ }
+ }
+
+ vmsvga_update_rect_delayed(s, x, y, w, h);
+}
+#endif
+
+struct vmsvga_cursor_definition_s {
+ int width;
+ int height;
+ int id;
+ int bpp;
+ int hot_x;
+ int hot_y;
+ uint32_t mask[1024];
+ uint32_t image[1024];
+};
+
+#define SVGA_BITMAP_SIZE(w, h) ((((w) + 31) >> 5) * (h))
+#define SVGA_PIXMAP_SIZE(w, h, bpp) (((((w) * (bpp)) + 31) >> 5) * (h))
+
+#ifdef HW_MOUSE_ACCEL
+static inline void vmsvga_cursor_define(struct vmsvga_state_s *s,
+ struct vmsvga_cursor_definition_s *c)
+{
+ int i;
+ for (i = SVGA_BITMAP_SIZE(c->width, c->height) - 1; i >= 0; i --)
+ c->mask[i] = ~c->mask[i];
+
+ if (s->ds->cursor_define)
+ s->ds->cursor_define(c->width, c->height, c->bpp, c->hot_x, c->hot_y,
+ (uint8_t *) c->image, (uint8_t *) c->mask);
+}
+#endif
+
+static inline int vmsvga_fifo_empty(struct vmsvga_state_s *s)
+{
+ if (!s->config || !s->enable)
+ return 0;
+ return (s->cmd->next_cmd == s->cmd->stop);
+}
+
+static inline uint32_t vmsvga_fifo_read(struct vmsvga_state_s *s)
+{
+ uint32_t cmd = s->fifo[s->cmd->stop >> 2];
+ s->cmd->stop += 4;
+ if (s->cmd->stop >= s->cmd->max)
+ s->cmd->stop = s->cmd->min;
+ return cmd;
+}
+
+static void vmsvga_fifo_run(struct vmsvga_state_s *s)
+{
+ uint32_t cmd, colour;
+ int args = 0;
+ int x, y, dx, dy, width, height;
+ struct vmsvga_cursor_definition_s cursor;
+ while (!vmsvga_fifo_empty(s))
+ switch (cmd = vmsvga_fifo_read(s)) {
+ case SVGA_CMD_UPDATE:
+ case SVGA_CMD_UPDATE_VERBOSE:
+ x = vmsvga_fifo_read(s);
+ y = vmsvga_fifo_read(s);
+ width = vmsvga_fifo_read(s);
+ height = vmsvga_fifo_read(s);
+ vmsvga_update_rect_delayed(s, x, y, width, height);
+ break;
+
+ case SVGA_CMD_RECT_FILL:
+ colour = vmsvga_fifo_read(s);
+ x = vmsvga_fifo_read(s);
+ y = vmsvga_fifo_read(s);
+ width = vmsvga_fifo_read(s);
+ height = vmsvga_fifo_read(s);
+#ifdef HW_FILL_ACCEL
+ vmsvga_fill_rect(s, colour, x, y, width, height);
+ break;
+#else
+ goto badcmd;
+#endif
+
+ case SVGA_CMD_RECT_COPY:
+ x = vmsvga_fifo_read(s);
+ y = vmsvga_fifo_read(s);
+ dx = vmsvga_fifo_read(s);
+ dy = vmsvga_fifo_read(s);
+ width = vmsvga_fifo_read(s);
+ height = vmsvga_fifo_read(s);
+#ifdef HW_RECT_ACCEL
+ vmsvga_copy_rect(s, x, y, dx, dy, width, height);
+ break;
+#else
+ goto badcmd;
+#endif
+
+ case SVGA_CMD_DEFINE_CURSOR:
+ cursor.id = vmsvga_fifo_read(s);
+ cursor.hot_x = vmsvga_fifo_read(s);
+ cursor.hot_y = vmsvga_fifo_read(s);
+ cursor.width = x = vmsvga_fifo_read(s);
+ cursor.height = y = vmsvga_fifo_read(s);
+ vmsvga_fifo_read(s);
+ cursor.bpp = vmsvga_fifo_read(s);
+ for (args = 0; args < SVGA_BITMAP_SIZE(x, y); args ++)
+ cursor.mask[args] = vmsvga_fifo_read(s);
+ for (args = 0; args < SVGA_PIXMAP_SIZE(x, y, cursor.bpp); args ++)
+ cursor.image[args] = vmsvga_fifo_read(s);
+#ifdef HW_MOUSE_ACCEL
+ vmsvga_cursor_define(s, &cursor);
+ break;
+#else
+ args = 0;
+ goto badcmd;
+#endif
+
+ /*
+ * Other commands that we at least know the number of arguments
+ * for so we can avoid FIFO desync if driver uses them illegally.
+ */
+ case SVGA_CMD_DEFINE_ALPHA_CURSOR:
+ vmsvga_fifo_read(s);
+ vmsvga_fifo_read(s);
+ vmsvga_fifo_read(s);
+ x = vmsvga_fifo_read(s);
+ y = vmsvga_fifo_read(s);
+ args = x * y;
+ goto badcmd;
+ case SVGA_CMD_RECT_ROP_FILL:
+ args = 6;
+ goto badcmd;
+ case SVGA_CMD_RECT_ROP_COPY:
+ args = 7;
+ goto badcmd;
+ case SVGA_CMD_DRAW_GLYPH_CLIPPED:
+ vmsvga_fifo_read(s);
+ vmsvga_fifo_read(s);
+ args = 7 + (vmsvga_fifo_read(s) >> 2);
+ goto badcmd;
+ case SVGA_CMD_SURFACE_ALPHA_BLEND:
+ args = 12;
+ goto badcmd;
+
+ /*
+ * Other commands that are not listed as depending on any
+ * CAPABILITIES bits, but are not described in the README either.
+ */
+ case SVGA_CMD_SURFACE_FILL:
+ case SVGA_CMD_SURFACE_COPY:
+ case SVGA_CMD_FRONT_ROP_FILL:
+ case SVGA_CMD_FENCE:
+ case SVGA_CMD_INVALID_CMD:
+ break; /* Nop */
+
+ default:
+ badcmd:
+ while (args --)
+ vmsvga_fifo_read(s);
+ printf("%s: Unknown command 0x%02x in SVGA command FIFO\n",
+ __FUNCTION__, cmd);
+ break;
+ }
+
+ s->syncing = 0;
+}
+
+static uint32_t vmsvga_index_read(void *opaque, uint32_t address)
+{
+ struct vmsvga_state_s *s = (struct vmsvga_state_s *) opaque;
+ return s->index;
+}
+
+static void vmsvga_index_write(void *opaque, uint32_t address, uint32_t index)
+{
+ struct vmsvga_state_s *s = (struct vmsvga_state_s *) opaque;
+ s->index = index;
+}
+
+static uint32_t vmsvga_value_read(void *opaque, uint32_t address)
+{
+ uint32_t caps;
+ struct vmsvga_state_s *s = (struct vmsvga_state_s *) opaque;
+ switch (s->index) {
+ case SVGA_REG_ID:
+ return s->svgaid;
+
+ case SVGA_REG_ENABLE:
+ return s->enable;
+
+ case SVGA_REG_WIDTH:
+ return s->width;
+
+ case SVGA_REG_HEIGHT:
+ return s->height;
+
+ case SVGA_REG_MAX_WIDTH:
+ return SVGA_MAX_WIDTH;
+
+ case SVGA_REG_MAX_HEIGHT:
+ return SVGA_MAX_WIDTH;
+
+ case SVGA_REG_DEPTH:
+ return s->depth;
+
+ case SVGA_REG_BITS_PER_PIXEL:
+ return (s->depth + 7) & ~7;
+
+ case SVGA_REG_PSEUDOCOLOR:
+ return 0x0;
+
+ case SVGA_REG_RED_MASK:
+ return s->wred;
+ case SVGA_REG_GREEN_MASK:
+ return s->wgreen;
+ case SVGA_REG_BLUE_MASK:
+ return s->wblue;
+
+ case SVGA_REG_BYTES_PER_LINE:
+ return ((s->depth + 7) >> 3) * s->new_width;
+
+ case SVGA_REG_FB_START:
+ return SVGA_MEM_BASE;
+
+ case SVGA_REG_FB_OFFSET:
+ return 0x0;
+
+ case SVGA_REG_VRAM_SIZE:
+ return s->vram_size - SVGA_FIFO_SIZE;
+
+ case SVGA_REG_FB_SIZE:
+ return s->fb_size;
+
+ case SVGA_REG_CAPABILITIES:
+ caps = SVGA_CAP_NONE;
+#ifdef HW_RECT_ACCEL
+ caps |= SVGA_CAP_RECT_COPY;
+#endif
+#ifdef HW_FILL_ACCEL
+ caps |= SVGA_CAP_RECT_FILL;
+#endif
+#ifdef HW_MOUSE_ACCEL
+ if (s->ds->mouse_set)
+ caps |= SVGA_CAP_CURSOR | SVGA_CAP_CURSOR_BYPASS_2 |
+ SVGA_CAP_CURSOR_BYPASS;
+#endif
+ return caps;
+
+ case SVGA_REG_MEM_START:
+ return SVGA_MEM_BASE + s->vram_size - SVGA_FIFO_SIZE;
+
+ case SVGA_REG_MEM_SIZE:
+ return SVGA_FIFO_SIZE;
+
+ case SVGA_REG_CONFIG_DONE:
+ return s->config;
+
+ case SVGA_REG_SYNC:
+ case SVGA_REG_BUSY:
+ return s->syncing;
+
+ case SVGA_REG_GUEST_ID:
+ return s->guest;
+
+ case SVGA_REG_CURSOR_ID:
+ return s->cursor.id;
+
+ case SVGA_REG_CURSOR_X:
+ return s->cursor.x;
+
+ case SVGA_REG_CURSOR_Y:
+ return s->cursor.x;
+
+ case SVGA_REG_CURSOR_ON:
+ return s->cursor.on;
+
+ case SVGA_REG_HOST_BITS_PER_PIXEL:
+ return (s->depth + 7) & ~7;
+
+ case SVGA_REG_SCRATCH_SIZE:
+ return s->scratch_size;
+
+ case SVGA_REG_MEM_REGS:
+ case SVGA_REG_NUM_DISPLAYS:
+ case SVGA_REG_PITCHLOCK:
+ case SVGA_PALETTE_BASE ... SVGA_PALETTE_END:
+ return 0;
+
+ default:
+ if (s->index >= SVGA_SCRATCH_BASE &&
+ s->index < SVGA_SCRATCH_BASE + s->scratch_size)
+ return s->scratch[s->index - SVGA_SCRATCH_BASE];
+ printf("%s: Bad register %02x\n", __FUNCTION__, s->index);
+ }
+
+ return 0;
+}
+
+static void vmsvga_value_write(void *opaque, uint32_t address, uint32_t value)
+{
+ struct vmsvga_state_s *s = (struct vmsvga_state_s *) opaque;
+ switch (s->index) {
+ case SVGA_REG_ID:
+ if (value == SVGA_ID_2 || value == SVGA_ID_1 || value == SVGA_ID_0)
+ s->svgaid = value;
+ break;
+
+ case SVGA_REG_ENABLE:
+ s->enable = s->config = value & s->config;
+ s->width = -1;
+ s->height = -1;
+ s->invalidated = 1;
+#ifdef EMBED_STDVGA
+ s->invalidate(opaque);
+#endif
+ if (s->enable)
+ s->fb_size = ((s->depth + 7) >> 3) * s->new_width * s->new_height;
+ break;
+
+ case SVGA_REG_WIDTH:
+ s->new_width = value;
+ s->invalidated = 1;
+ break;
+
+ case SVGA_REG_HEIGHT:
+ s->new_height = value;
+ s->invalidated = 1;
+ break;
+
+ case SVGA_REG_DEPTH:
+ case SVGA_REG_BITS_PER_PIXEL:
+ if (value != s->depth) {
+ printf("%s: Bad colour depth: %i bits\n", __FUNCTION__, value);
+ s->config = 0;
+ }
+ break;
+
+ case SVGA_REG_CONFIG_DONE:
+ if (value) {
+ s->fifo = (uint32_t *) &s->vram[s->vram_size - SVGA_FIFO_SIZE];
+ /* Check range and alignment. */
+ if ((s->cmd->min | s->cmd->max |
+ s->cmd->next_cmd | s->cmd->stop) & 3)
+ break;
+ if (s->cmd->min < (uint8_t *) s->cmd->fifo - (uint8_t *) s->fifo)
+ break;
+ if (s->cmd->max > SVGA_FIFO_SIZE)
+ break;
+ if (s->cmd->max < s->cmd->min + 10 * 1024)
+ break;
+ }
+ s->config = value;
+ break;
+
+ case SVGA_REG_SYNC:
+ s->syncing = 1;
+ vmsvga_fifo_run(s); /* Or should we just wait for update_display? */
+ break;
+
+ case SVGA_REG_GUEST_ID:
+ s->guest = value;
+#ifdef VERBOSE
+ if (value >= GUEST_OS_BASE && value < GUEST_OS_BASE +
+ sizeof(vmsvga_guest_id) / sizeof(*vmsvga_guest_id))
+ printf("%s: guest runs %s.\n", __FUNCTION__,
+ vmsvga_guest_id[value - GUEST_OS_BASE]);
+#endif
+ break;
+
+ case SVGA_REG_CURSOR_ID:
+ s->cursor.id = value;
+ break;
+
+ case SVGA_REG_CURSOR_X:
+ s->cursor.x = value;
+ break;
+
+ case SVGA_REG_CURSOR_Y:
+ s->cursor.y = value;
+ break;
+
+ case SVGA_REG_CURSOR_ON:
+ s->cursor.on |= (value == SVGA_CURSOR_ON_SHOW);
+ s->cursor.on &= (value != SVGA_CURSOR_ON_HIDE);
+#ifdef HW_MOUSE_ACCEL
+ if (s->ds->mouse_set && value <= SVGA_CURSOR_ON_SHOW)
+ s->ds->mouse_set(s->cursor.x, s->cursor.y, s->cursor.on);
+#endif
+ break;
+
+ case SVGA_REG_MEM_REGS:
+ case SVGA_REG_NUM_DISPLAYS:
+ case SVGA_REG_PITCHLOCK:
+ case SVGA_PALETTE_BASE ... SVGA_PALETTE_END:
+ break;
+
+ default:
+ if (s->index >= SVGA_SCRATCH_BASE &&
+ s->index < SVGA_SCRATCH_BASE + s->scratch_size) {
+ s->scratch[s->index - SVGA_SCRATCH_BASE] = value;
+ break;
+ }
+ printf("%s: Bad register %02x\n", __FUNCTION__, s->index);
+ }
+}
+
+static uint32_t vmsvga_bios_read(void *opaque, uint32_t address)
+{
+ printf("%s: what are we supposed to return?\n", __FUNCTION__);
+ return 0xcafe;
+}
+
+static void vmsvga_bios_write(void *opaque, uint32_t address, uint32_t data)
+{
+ printf("%s: what are we supposed to do with (%08x)?\n",
+ __FUNCTION__, data);
+}
+
+static inline void vmsvga_size(struct vmsvga_state_s *s)
+{
+ if (s->new_width != s->width || s->new_height != s->height) {
+ s->width = s->new_width;
+ s->height = s->new_height;
+ dpy_resize(s->ds, s->width, s->height);
+ s->invalidated = 1;
+ }
+}
+
+static void vmsvga_update_display(void *opaque)
+{
+ struct vmsvga_state_s *s = (struct vmsvga_state_s *) opaque;
+ if (!s->enable) {
+#ifdef EMBED_STDVGA
+ s->update(opaque);
+#endif
+ return;
+ }
+
+ vmsvga_size(s);
+
+ vmsvga_fifo_run(s);
+ vmsvga_update_rect_flush(s);
+
+ /*
+ * Is it more efficient to look at vram VGA-dirty bits or wait
+ * for the driver to issue SVGA_CMD_UPDATE?
+ */
+ if (s->invalidated) {
+ s->invalidated = 0;
+ vmsvga_update_screen(s);
+ }
+}
+
+static void vmsvga_reset(struct vmsvga_state_s *s)
+{
+ s->index = 0;
+ s->enable = 0;
+ s->config = 0;
+ s->width = -1;
+ s->height = -1;
+ s->svgaid = SVGA_ID;
+ s->depth = s->ds->depth ? s->ds->depth : 24;
+ s->bypp = (s->depth + 7) >> 3;
+ s->cursor.on = 0;
+ s->redraw_fifo_first = 0;
+ s->redraw_fifo_last = 0;
+ switch (s->depth) {
+ case 8:
+ s->wred = 0x00000007;
+ s->wgreen = 0x00000038;
+ s->wblue = 0x000000c0;
+ break;
+ case 15:
+ s->wred = 0x0000001f;
+ s->wgreen = 0x000003e0;
+ s->wblue = 0x00007c00;
+ break;
+ case 16:
+ s->wred = 0x0000001f;
+ s->wgreen = 0x000007e0;
+ s->wblue = 0x0000f800;
+ break;
+ case 24:
+ s->wred = 0x000000ff;
+ s->wgreen = 0x0000ff00;
+ s->wblue = 0x00ff0000;
+ break;
+ case 32:
+ s->wred = 0x000000ff;
+ s->wgreen = 0x0000ff00;
+ s->wblue = 0x00ff0000;
+ break;
+ }
+ s->syncing = 0;
+}
+
+static void vmsvga_invalidate_display(void *opaque)
+{
+ struct vmsvga_state_s *s = (struct vmsvga_state_s *) opaque;
+ if (!s->enable) {
+#ifdef EMBED_STDVGA
+ s->invalidate(opaque);
+#endif
+ return;
+ }
+
+ s->invalidated = 1;
+}
+
+static void vmsvga_screen_dump(void *opaque, const char *filename)
+{
+ struct vmsvga_state_s *s = (struct vmsvga_state_s *) opaque;
+ if (!s->enable) {
+#ifdef EMBED_STDVGA
+ s->screen_dump(opaque, filename);
+#endif
+ return;
+ }
+
+ /* TODO */
+}
+
+#ifdef DIRECT_VRAM
+static uint32_t vmsvga_vram_readb(void *opaque, target_phys_addr_t addr)
+{
+ struct vmsvga_state_s *s = (struct vmsvga_state_s *) opaque;
+ addr -= SVGA_MEM_BASE;
+ if (addr < s->fb_size)
+ return *(uint8_t *) (s->ds->data + addr);
+ else
+ return *(uint8_t *) (s->vram + addr);
+}
+
+static uint32_t vmsvga_vram_readw(void *opaque, target_phys_addr_t addr)
+{
+ struct vmsvga_state_s *s = (struct vmsvga_state_s *) opaque;
+ addr -= SVGA_MEM_BASE;
+ if (addr < s->fb_size)
+ return *(uint16_t *) (s->ds->data + addr);
+ else
+ return *(uint16_t *) (s->vram + addr);
+}
+
+static uint32_t vmsvga_vram_readl(void *opaque, target_phys_addr_t addr)
+{
+ struct vmsvga_state_s *s = (struct vmsvga_state_s *) opaque;
+ addr -= SVGA_MEM_BASE;
+ if (addr < s->fb_size)
+ return *(uint32_t *) (s->ds->data + addr);
+ else
+ return *(uint32_t *) (s->vram + addr);
+}
+
+static void vmsvga_vram_writeb(void *opaque, target_phys_addr_t addr,
+ uint32_t value)
+{
+ struct vmsvga_state_s *s = (struct vmsvga_state_s *) opaque;
+ addr -= SVGA_MEM_BASE;
+ if (addr < s->fb_size)
+ *(uint8_t *) (s->ds->data + addr) = value;
+ else
+ *(uint8_t *) (s->vram + addr) = value;
+}
+
+static void vmsvga_vram_writew(void *opaque, target_phys_addr_t addr,
+ uint32_t value)
+{
+ struct vmsvga_state_s *s = (struct vmsvga_state_s *) opaque;
+ addr -= SVGA_MEM_BASE;
+ if (addr < s->fb_size)
+ *(uint16_t *) (s->ds->data + addr) = value;
+ else
+ *(uint16_t *) (s->vram + addr) = value;
+}
+
+static void vmsvga_vram_writel(void *opaque, target_phys_addr_t addr,
+ uint32_t value)
+{
+ struct vmsvga_state_s *s = (struct vmsvga_state_s *) opaque;
+ addr -= SVGA_MEM_BASE;
+ if (addr < s->fb_size)
+ *(uint32_t *) (s->ds->data + addr) = value;
+ else
+ *(uint32_t *) (s->vram + addr) = value;
+}
+
+static CPUReadMemoryFunc *vmsvga_vram_read[] = {
+ vmsvga_vram_readb,
+ vmsvga_vram_readw,
+ vmsvga_vram_readl,
+};
+
+static CPUWriteMemoryFunc *vmsvga_vram_write[] = {
+ vmsvga_vram_writeb,
+ vmsvga_vram_writew,
+ vmsvga_vram_writel,
+};
+#endif
+
+static void vmsvga_save(struct vmsvga_state_s *s, QEMUFile *f)
+{
+ qemu_put_be32s(f, &s->depth);
+ qemu_put_be32s(f, &s->enable);
+ qemu_put_be32s(f, &s->config);
+ qemu_put_be32s(f, &s->cursor.id);
+ qemu_put_be32s(f, &s->cursor.x);
+ qemu_put_be32s(f, &s->cursor.y);
+ qemu_put_be32s(f, &s->cursor.on);
+ qemu_put_be32s(f, &s->index);
+ qemu_put_buffer(f, (uint8_t *) s->scratch, s->scratch_size * 4);
+ qemu_put_be32s(f, &s->new_width);
+ qemu_put_be32s(f, &s->new_height);
+ qemu_put_be32s(f, &s->guest);
+ qemu_put_be32s(f, &s->svgaid);
+ qemu_put_be32s(f, &s->syncing);
+ qemu_put_be32s(f, &s->fb_size);
+}
+
+static int vmsvga_load(struct vmsvga_state_s *s, QEMUFile *f)
+{
+ int depth;
+ qemu_get_be32s(f, &depth);
+ qemu_get_be32s(f, &s->enable);
+ qemu_get_be32s(f, &s->config);
+ qemu_get_be32s(f, &s->cursor.id);
+ qemu_get_be32s(f, &s->cursor.x);
+ qemu_get_be32s(f, &s->cursor.y);
+ qemu_get_be32s(f, &s->cursor.on);
+ qemu_get_be32s(f, &s->index);
+ qemu_get_buffer(f, (uint8_t *) s->scratch, s->scratch_size * 4);
+ qemu_get_be32s(f, &s->new_width);
+ qemu_get_be32s(f, &s->new_height);
+ qemu_get_be32s(f, &s->guest);
+ qemu_get_be32s(f, &s->svgaid);
+ qemu_get_be32s(f, &s->syncing);
+ qemu_get_be32s(f, &s->fb_size);
+
+ if (s->enable && depth != s->depth) {
+ printf("%s: need colour depth of %i bits to resume operation.\n",
+ __FUNCTION__, depth);
+ return -EINVAL;
+ }
+
+ s->invalidated = 1;
+ if (s->config)
+ s->fifo = (uint32_t *) &s->vram[s->vram_size - SVGA_FIFO_SIZE];
+
+ return 0;
+}
+
+static void vmsvga_init(struct vmsvga_state_s *s, DisplayState *ds,
+ uint8_t *vga_ram_base, unsigned long vga_ram_offset,
+ int vga_ram_size)
+{
+ int iomemtype;
+ s->ds = ds;
+ s->vram = vga_ram_base;
+ s->vram_size = vga_ram_size;
+
+ s->scratch_size = SVGA_SCRATCH_SIZE;
+ s->scratch = (uint32_t *) qemu_malloc(s->scratch_size * 4);
+
+ vmsvga_reset(s);
+
+#ifdef DIRECT_VRAM
+ iomemtype = cpu_register_io_memory(0, vmsvga_vram_read,
+ vmsvga_vram_write, s);
+#else
+ iomemtype = vga_ram_offset | IO_MEM_RAM;
+#endif
+ cpu_register_physical_memory(SVGA_MEM_BASE, vga_ram_size,
+ iomemtype);
+
+ register_ioport_read(SVGA_IO_BASE + SVGA_IO_MUL * SVGA_INDEX_PORT,
+ 1, 4, vmsvga_index_read, s);
+ register_ioport_write(SVGA_IO_BASE + SVGA_IO_MUL * SVGA_INDEX_PORT,
+ 1, 4, vmsvga_index_write, s);
+ register_ioport_read(SVGA_IO_BASE + SVGA_IO_MUL * SVGA_VALUE_PORT,
+ 1, 4, vmsvga_value_read, s);
+ register_ioport_write(SVGA_IO_BASE + SVGA_IO_MUL * SVGA_VALUE_PORT,
+ 1, 4, vmsvga_value_write, s);
+ register_ioport_read(SVGA_IO_BASE + SVGA_IO_MUL * SVGA_BIOS_PORT,
+ 1, 4, vmsvga_bios_read, s);
+ register_ioport_write(SVGA_IO_BASE + SVGA_IO_MUL * SVGA_BIOS_PORT,
+ 1, 4, vmsvga_bios_write, s);
+
+ graphic_console_init(ds, vmsvga_update_display,
+ vmsvga_invalidate_display, vmsvga_screen_dump, s);
+
+#ifdef EMBED_STDVGA
+ vga_common_init((VGAState *) s, ds,
+ vga_ram_base, vga_ram_offset, vga_ram_size);
+ vga_init((VGAState *) s);
+#endif
+}
+
+static void pci_vmsvga_save(QEMUFile *f, void *opaque)
+{
+ struct pci_vmsvga_state_s *s = (struct pci_vmsvga_state_s *) opaque;
+ pci_device_save(&s->card, f);
+ vmsvga_save(&s->chip, f);
+}
+
+static int pci_vmsvga_load(QEMUFile *f, void *opaque, int version_id)
+{
+ struct pci_vmsvga_state_s *s = (struct pci_vmsvga_state_s *) opaque;
+ int ret;
+
+ ret = pci_device_load(&s->card, f);
+ if (ret < 0)
+ return ret;
+
+ ret = vmsvga_load(&s->chip, f);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+#define PCI_VENDOR_ID_VMWARE 0x15ad
+#define PCI_DEVICE_ID_VMWARE_SVGA2 0x0405
+#define PCI_DEVICE_ID_VMWARE_SVGA 0x0710
+#define PCI_DEVICE_ID_VMWARE_NET 0x0720
+#define PCI_DEVICE_ID_VMWARE_SCSI 0x0730
+#define PCI_DEVICE_ID_VMWARE_IDE 0x1729
+#define PCI_CLASS_BASE_DISPLAY 0x03
+#define PCI_CLASS_SUB_VGA 0x00
+#define PCI_CLASS_HEADERTYPE_00h 0x00
+
+void pci_vmsvga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base,
+ unsigned long vga_ram_offset, int vga_ram_size)
+{
+ struct pci_vmsvga_state_s *s;
+
+ /* Setup PCI configuration */
+ s = (struct pci_vmsvga_state_s *)
+ pci_register_device(bus, "QEMUware SVGA",
+ sizeof(struct pci_vmsvga_state_s), -1, 0, 0);
+ s->card.config[PCI_VENDOR_ID] = PCI_VENDOR_ID_VMWARE & 0xff;
+ s->card.config[PCI_VENDOR_ID + 1] = PCI_VENDOR_ID_VMWARE >> 8;
+ s->card.config[PCI_DEVICE_ID] = SVGA_PCI_DEVICE_ID & 0xff;
+ s->card.config[PCI_DEVICE_ID + 1] = SVGA_PCI_DEVICE_ID >> 8;
+ s->card.config[PCI_COMMAND] = 0x07; /* I/O + Memory */
+ s->card.config[PCI_CLASS_DEVICE] = PCI_CLASS_SUB_VGA;
+ s->card.config[0x0b] = PCI_CLASS_BASE_DISPLAY;
+ s->card.config[0x0c] = 0x08; /* Cache line size */
+ s->card.config[0x0d] = 0x40; /* Latency timer */
+ s->card.config[0x0e] = PCI_CLASS_HEADERTYPE_00h;
+ s->card.config[0x10] = ((SVGA_IO_BASE >> 0) & 0xff) | 1;
+ s->card.config[0x11] = (SVGA_IO_BASE >> 8) & 0xff;
+ s->card.config[0x12] = (SVGA_IO_BASE >> 16) & 0xff;
+ s->card.config[0x13] = (SVGA_IO_BASE >> 24) & 0xff;
+ s->card.config[0x18] = (SVGA_MEM_BASE >> 0) & 0xff;
+ s->card.config[0x19] = (SVGA_MEM_BASE >> 8) & 0xff;
+ s->card.config[0x1a] = (SVGA_MEM_BASE >> 16) & 0xff;
+ s->card.config[0x1b] = (SVGA_MEM_BASE >> 24) & 0xff;
+ s->card.config[0x2c] = PCI_VENDOR_ID_VMWARE & 0xff;
+ s->card.config[0x2d] = PCI_VENDOR_ID_VMWARE >> 8;
+ s->card.config[0x2e] = SVGA_PCI_DEVICE_ID & 0xff;
+ s->card.config[0x2f] = SVGA_PCI_DEVICE_ID >> 8;
+ s->card.config[0x3c] = 0xff; /* End */
+
+ vmsvga_init(&s->chip, ds, vga_ram_base, vga_ram_offset, vga_ram_size);
+
+ register_savevm("vmware_vga", 0, 0, pci_vmsvga_save, pci_vmsvga_load, s);
+}
Modified: trunk/src/host/qemu-neo1973/hw/wm8750.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/wm8750.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/wm8750.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -16,8 +16,9 @@
struct wm_rate_s;
struct wm8750_s {
- int i2c_dir;
- struct i2c_slave_s i2c;
+ i2c_slave i2c;
+ uint8_t i2c_data[2];
+ int i2c_len;
QEMUSoundCard card;
SWVoiceIn *adc_voice[IN_PORT_N];
SWVoiceOut *dac_voice[OUT_PORT_N];
@@ -207,9 +208,9 @@
(s->mute ? NONE : BOTH);
}
-void wm8750_reset(struct i2c_slave_s *i2c)
+void wm8750_reset(i2c_slave *i2c)
{
- struct wm8750_s *s = (struct wm8750_s *) i2c->opaque;
+ struct wm8750_s *s = (struct wm8750_s *) i2c;
s->enable = 0;
wm8750_set_format(s);
s->diff[0] = 0;
@@ -245,12 +246,27 @@
s->idx_out = 0;
s->req_out = 0;
wm8750_mask_update(s);
+ s->i2c_len = 0;
}
-static void wm8750_start(void *opaque, int dir)
+static void wm8750_event(i2c_slave *i2c, enum i2c_event event)
{
- struct wm8750_s *s = (struct wm8750_s *) opaque;
- s->i2c_dir = dir;
+ struct wm8750_s *s = (struct wm8750_s *) i2c;
+
+ switch (event) {
+ case I2C_START_SEND:
+ s->i2c_len = 0;
+ break;
+ case I2C_FINISH:
+#ifdef VERBOSE
+ if (s->i2c_len < 2)
+ printf("%s: message too short (%i bytes)\n",
+ __FUNCTION__, s->i2c_len);
+#endif
+ break;
+ default:
+ break;
+ }
}
#define WM8750_LINVOL 0x00
@@ -290,27 +306,25 @@
#define WM8750_ROUT2V 0x29
#define WM8750_MOUTV 0x2a
-static int wm8750_tx(void *opaque, uint8_t *data, int len)
+static int wm8750_tx(i2c_slave *i2c, uint8_t data)
{
- struct wm8750_s *s = (struct wm8750_s *) opaque;
+ struct wm8750_s *s = (struct wm8750_s *) i2c;
uint8_t cmd;
uint16_t value;
- if (s->i2c_dir)
+ if (s->i2c_len >= 2) {
+ printf("%s: long message (%i bytes)\n", __FUNCTION__, s->i2c_len);
+#ifdef VERBOSE
return 1;
- if (len < 2) {
-#ifdef VERBOSE
- printf("%s: message too short (%i bytes)\n", __FUNCTION__, len);
#endif
+ }
+ s->i2c_data[s->i2c_len ++] = data;
+ if (s->i2c_len != 2)
return 0;
- }
- cmd = data[0] >> 1;
- value = ((data[0] << 8) | data[1]) & 0x1ff;
-#ifdef VERBOSE
- if (len > 2)
- printf("%s: long message (%i bytes)\n", __FUNCTION__, len);
-#endif
+ cmd = s->i2c_data[0] >> 1;
+ value = ((s->i2c_data[0] << 8) | s->i2c_data[1]) & 0x1ff;
+
switch (cmd) {
case WM8750_LADCIN: /* ADC Signal Path Control (Left) */
s->diff[0] = (((value >> 6) & 3) == 3); /* LINSEL */
@@ -472,30 +486,36 @@
return 0;
}
-struct i2c_slave_s *wm8750_init(AudioState *audio)
+static int wm8750_rx(i2c_slave *i2c)
{
- struct wm8750_s *s = qemu_mallocz(sizeof(struct wm8750_s));
- s->i2c.opaque = s;
- s->i2c.tx = wm8750_tx;
- s->i2c.start = wm8750_start;
+ return 0x00;
+}
+i2c_slave *wm8750_init(i2c_bus *bus, AudioState *audio)
+{
+ struct wm8750_s *s = (struct wm8750_s *)
+ i2c_slave_init(bus, 0, sizeof(struct wm8750_s));
+ s->i2c.event = wm8750_event;
+ s->i2c.recv = wm8750_rx;
+ s->i2c.send = wm8750_tx;
+
AUD_register_card(audio, CODEC, &s->card);
wm8750_reset(&s->i2c);
return &s->i2c;
}
-void wm8750_fini(struct i2c_slave_s *i2c)
+void wm8750_fini(i2c_slave *i2c)
{
- struct wm8750_s *s = (struct wm8750_s *) i2c->opaque;
+ struct wm8750_s *s = (struct wm8750_s *) i2c;
wm8750_reset(&s->i2c);
AUD_remove_card(&s->card);
qemu_free(s);
}
-void wm8750_data_req_set(struct i2c_slave_s *i2c,
+void wm8750_data_req_set(i2c_slave *i2c,
void (*data_req)(void *, int, int), void *opaque)
{
- struct wm8750_s *s = (struct wm8750_s *) i2c->opaque;
+ struct wm8750_s *s = (struct wm8750_s *) i2c;
s->data_req = data_req;
s->opaque = opaque;
}
Modified: trunk/src/host/qemu-neo1973/hw/wm8753.c
===================================================================
--- trunk/src/host/qemu-neo1973/hw/wm8753.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/hw/wm8753.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -16,8 +16,9 @@
struct wm_rate_s;
struct wm8753_s {
- int i2c_dir;
- struct i2c_slave_s i2c;
+ i2c_slave i2c;
+ uint8_t i2c_data[2];
+ int i2c_len;
QEMUSoundCard card;
SWVoiceIn *adc_voice[IN_PORT_N];
SWVoiceOut *dac_voice[OUT_PORT_N];
@@ -48,10 +49,10 @@
uint8_t intintr;
uint8_t intprev;
struct {
- gpio_handler_t fn;
- void *opaque;
+ qemu_irq handler;
enum { input, low, high, intr } type;
- } handler[8];
+ } line[8];
+ qemu_irq *gpio_in;
uint8_t response;
@@ -219,24 +220,23 @@
while ((line = ffs(level))) {
line --;
- if (s->handler[line].fn)
- s->handler[line].fn(line, (s->intprev >> line) & 1,
- s->handler[line].opaque);
+ if (s->line[line].handler)
+ qemu_set_irq(s->line[line].handler, (s->intprev >> line) & 1);
level ^= 1 << line;
}
}
static inline void wm8753_input_update(struct wm8753_s *s, int line)
{
- if (s->handler[line].type == input)
+ if (s->line[line].type == input)
s->intinput |= 1 << line;
else
s->intinput &= ~(1 << line);
- if (s->handler[line].type == high)
+ if (s->line[line].type == high)
s->inthigh |= 1 << line;
else
s->inthigh &= ~(1 << line);
- if (s->handler[line].type == intr)
+ if (s->line[line].type == intr)
s->intintr |= 1 << line;
else
s->intintr &= ~(1 << line);
@@ -283,10 +283,10 @@
return 0;
}
-void wm8753_reset(struct i2c_slave_s *i2c)
+void wm8753_reset(i2c_slave *i2c)
{
int i;
- struct wm8753_s *s = (struct wm8753_s *) i2c->opaque;
+ struct wm8753_s *s = (struct wm8753_s *) i2c;
s->enable = 0;
wm8753_set_format(s);
@@ -326,7 +326,7 @@
s->inthigh = 0x00;
s->intintr = 0x00;
for (i = 0; i < 8; i ++)
- s->handler[i].type = input;
+ s->line[i].type = input;
s->power[0] = 0x000;
s->power[1] = 0x000;
@@ -346,10 +346,24 @@
wm8753_mask_update(s);
}
-static void wm8753_start(void *opaque, int dir)
+static void wm8753_event(i2c_slave *i2c, enum i2c_event event)
{
- struct wm8753_s *s = (struct wm8753_s *) opaque;
- s->i2c_dir = dir;
+ struct wm8753_s *s = (struct wm8753_s *) i2c;
+
+ switch (event) {
+ case I2C_START_SEND:
+ s->i2c_len = 0;
+ break;
+ case I2C_FINISH:
+#ifdef VERBOSE
+ if (s->i2c_len < 2)
+ printf("%s: message too short (%i bytes)\n",
+ __FUNCTION__, s->i2c_len);
+#endif
+ break;
+ default:
+ break;
+ }
}
#define WM8753_DAC 0x01
@@ -413,27 +427,25 @@
#define WM8753_BIASCTL 0x3d
#define WM8753_ADCTL2 0x3f
-static int wm8753_tx(void *opaque, uint8_t *data, int len)
+static int wm8753_tx(i2c_slave *i2c, uint8_t data)
{
- struct wm8753_s *s = (struct wm8753_s *) opaque;
+ struct wm8753_s *s = (struct wm8753_s *) i2c;
uint8_t cmd;
uint16_t value;
- if (s->i2c_dir)
+ if (s->i2c_len >= 2) {
+ printf("%s: long message (%i bytes)\n", __FUNCTION__, s->i2c_len);
+#ifdef VERBOSE
return 1;
- if (len < 2) {
-#ifdef VERBOSE
- printf("%s: message too short (%i bytes)\n", __FUNCTION__, len);
#endif
+ }
+ s->i2c_data[s->i2c_len ++] = data;
+ if (s->i2c_len != 2)
return 0;
- }
- cmd = data[0] >> 1;
- value = ((data[0] << 8) | data[1]) & 0x1ff;
-#ifdef VERBOSE
- if (len > 2)
- printf("%s: long message (%i bytes)\n", __FUNCTION__, len);
-#endif
+ cmd = s->i2c_data[0] >> 1;
+ value = ((s->i2c_data[0] << 8) | s->i2c_data[1]) & 0x1ff;
+
switch (cmd) {
case WM8753_ADCIN: /* ADC Input Mode */
s->adcin = value;
@@ -601,17 +613,17 @@
case WM8753_GPIO1: /* GPIO Control (1) */
s->inten = !!(value & 3);
switch ((value >> 3) & 3) {
- case 0: s->handler[5].type = input; break;
- case 1: s->handler[5].type = intr; break;
- case 2: s->handler[5].type = low; break;
- case 3: s->handler[5].type = high; break;
+ case 0: s->line[5].type = input; break;
+ case 1: s->line[5].type = intr; break;
+ case 2: s->line[5].type = low; break;
+ case 3: s->line[5].type = high; break;
}
wm8753_input_update(s, 5);
switch ((value >> 0) & 7) {
- case 4: s->handler[4].type = low; break;
- case 5: s->handler[4].type = high; break;
- case 7: s->handler[4].type = intr; break;
- default: s->handler[4].type = input; break;
+ case 4: s->line[4].type = low; break;
+ case 5: s->line[4].type = high; break;
+ case 7: s->line[4].type = intr; break;
+ default: s->line[4].type = input; break;
}
wm8753_input_update(s, 4);
wm8753_int_update(s);
@@ -619,24 +631,24 @@
case WM8753_GPIO2: /* GPIO Control (2) */
switch ((value >> 6) & 7) {
- case 4: s->handler[3].type = low; break;
- case 5: s->handler[3].type = high; break;
- case 7: s->handler[3].type = intr; break;
- default: s->handler[3].type = input; break;
+ case 4: s->line[3].type = low; break;
+ case 5: s->line[3].type = high; break;
+ case 7: s->line[3].type = intr; break;
+ default: s->line[3].type = input; break;
}
wm8753_input_update(s, 3);
switch ((value >> 3) & 7) {
- case 0: s->handler[2].type = low; break;
- case 1: s->handler[2].type = high; break;
- case 3: s->handler[2].type = intr; break;
- default: s->handler[2].type = input; break;
+ case 0: s->line[2].type = low; break;
+ case 1: s->line[2].type = high; break;
+ case 3: s->line[2].type = intr; break;
+ default: s->line[2].type = input; break;
}
wm8753_input_update(s, 2);
switch ((value >> 0) & 7) {
- case 0: s->handler[1].type = low; break;
- case 1: s->handler[1].type = high; break;
- case 3: s->handler[1].type = intr; break;
- default: s->handler[1].type = input; break;
+ case 0: s->line[1].type = low; break;
+ case 1: s->line[1].type = high; break;
+ case 3: s->line[1].type = intr; break;
+ default: s->line[1].type = input; break;
}
wm8753_input_update(s, 1);
wm8753_int_update(s);
@@ -688,52 +700,64 @@
return 0;
}
-struct i2c_slave_s *wm8753_init(AudioState *audio)
+static int wm8753_rx(i2c_slave *i2c)
{
- struct wm8753_s *s = qemu_mallocz(sizeof(struct wm8753_s));
- s->i2c.opaque = s;
- s->i2c.tx = wm8753_tx;
- s->i2c.start = wm8753_start;
+ return 0x00;
+}
+static void wm8753_gpio_set(void *opaque, int line, int level)
+{
+ struct wm8753_s *s = (struct wm8753_s *) opaque;
+ if (level)
+ s->intlevel |= 1 << line;
+ else
+ s->intlevel &= ~(1 << line);
+ wm8753_int_update(s);
+}
+
+i2c_slave *wm8753_init(i2c_bus *bus, AudioState *audio)
+{
+ struct wm8753_s *s = (struct wm8753_s *)
+ i2c_slave_init(bus, 0, sizeof(struct wm8753_s));
+ s->i2c.event = wm8753_event;
+ s->i2c.recv = wm8753_rx;
+ s->i2c.send = wm8753_tx;
+ s->gpio_in = qemu_allocate_irqs(wm8753_gpio_set, s, 8);
+
AUD_register_card(audio, CODEC, &s->card);
wm8753_reset(&s->i2c);
return &s->i2c;
}
-void wm8753_fini(struct i2c_slave_s *i2c)
+void wm8753_fini(i2c_slave *i2c)
{
- struct wm8753_s *s = (struct wm8753_s *) i2c->opaque;
+ struct wm8753_s *s = (struct wm8753_s *) i2c;
wm8753_reset(&s->i2c);
AUD_remove_card(&s->card);
qemu_free(s);
}
-void wm8753_gpio_set(struct i2c_slave_s *i2c, int line, int level)
+qemu_irq *wm8753_gpio_in_get(i2c_slave *i2c)
{
- struct wm8753_s *s = (struct wm8753_s *) i2c->opaque;
- if (level)
- s->intlevel |= 1 << line;
- else
- s->intlevel &= ~(1 << line);
- wm8753_int_update(s);
+ struct wm8753_s *s = (struct wm8753_s *) i2c;
+ return s->gpio_in;
}
-void wm8753_gpio_handler_set(struct i2c_slave_s *i2c, int line,
- gpio_handler_t handler, void *opaque) {
- struct wm8753_s *s = (struct wm8753_s *) i2c->opaque;
+void wm8753_gpio_out_set(i2c_slave *i2c, int line, qemu_irq handler)
+{
+ struct wm8753_s *s = (struct wm8753_s *) i2c;
if (line >= 8) {
printf("%s: No GPIO pin %i\n", __FUNCTION__, line);
return;
}
- s->handler[line].fn = handler;
- s->handler[line].opaque = opaque;
+ s->line[line].handler = handler;
}
-void wm8753_data_req_set(struct i2c_slave_s *i2c,
+void wm8753_data_req_set(i2c_slave *i2c,
void (*data_req)(void *, int, int), void *opaque)
{
- struct wm8753_s *s = (struct wm8753_s *) i2c->opaque;
+ struct wm8753_s *s = (struct wm8753_s *) i2c;
s->data_req = data_req;
s->opaque = opaque;
}
Deleted: trunk/src/host/qemu-neo1973/keymaps/zaurus
===================================================================
--- trunk/src/host/qemu-neo1973/keymaps/zaurus 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/keymaps/zaurus 2007-05-11 23:44:50 UTC (rev 1948)
@@ -1,26 +0,0 @@
-# Keymap for the Zaurus series devices
-include common
-slash 0x33 shift
-question 0x34 shift
-exclam 0x02 shift
-quotedbl 0x03 shift
-numbersign 0x04 shift
-dollar 0x05 shift
-percent 0x06 shift
-ampersand 0x07 shift
-apostrophe 0x08 shift
-parenleft 0x09 shift
-parenright 0x0a shift
-asciitilde 0x0b shift
-at 0x0c shift
-BackSpace 0xe
-Delete 0xe altgr
-Tab 0xf
-Caps_Lock 0xf altgr
-asciicircum 0x11 altgr
-equal 0x12 altgr
-plus 0x13 altgr
-bracketleft 0x14 altgr
-bracketright 0x15 altgr
-Page_Up 0xc8 altgr
-Page_Down 0xcd altgr
Modified: trunk/src/host/qemu-neo1973/keymaps.c
===================================================================
--- trunk/src/host/qemu-neo1973/keymaps.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/keymaps.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -84,7 +84,7 @@
*end_of_keysym = 0;
keysym = get_keysym(line);
if (keysym == 0) {
- fprintf(stderr, "Warning: unknown keysym %s\n", line);
+ // fprintf(stderr, "Warning: unknown keysym %s\n", line);
} else {
const char *rest = end_of_keysym + 1;
int keycode = strtol(rest, NULL, 0);
Modified: trunk/src/host/qemu-neo1973/kqemu.c
===================================================================
--- trunk/src/host/qemu-neo1973/kqemu.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/kqemu.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -26,6 +26,9 @@
#include <sys/mman.h>
#include <sys/ioctl.h>
#endif
+#ifdef HOST_SOLARIS
+#include <sys/ioccom.h>
+#endif
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
@@ -174,7 +177,8 @@
kqemu_fd = open(KQEMU_DEVICE, O_RDWR);
#endif
if (kqemu_fd == KQEMU_INVALID_FD) {
- fprintf(stderr, "Could not open '%s' - QEMU acceleration layer not activated\n", KQEMU_DEVICE);
+ fprintf(stderr, "Could not open '%s' - QEMU acceleration layer not activated: %s\n",
+ KQEMU_DEVICE, strerror(errno));
return -1;
}
version = 0;
@@ -480,7 +484,7 @@
cpu_x86_set_cpl(env, 0);
cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc,
0, 0xffffffff,
- DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
+ DESC_G_MASK | DESC_P_MASK |
DESC_S_MASK |
DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK);
cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc,
Deleted: trunk/src/host/qemu-neo1973/linux-2.6.9-qemu-fast.patch
===================================================================
--- trunk/src/host/qemu-neo1973/linux-2.6.9-qemu-fast.patch 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/linux-2.6.9-qemu-fast.patch 2007-05-11 23:44:50 UTC (rev 1948)
@@ -1,70 +0,0 @@
---- linux-2.6.9/arch/i386/Kconfig 2004-10-18 23:53:22.000000000 +0200
-+++ linux-2.6.9-qemu/arch/i386/Kconfig 2004-12-07 21:56:49.000000000 +0100
-@@ -337,6 +337,14 @@ config X86_GENERIC
-
- endif
-
-+config QEMU
-+ bool "Kernel to run under QEMU"
-+ depends on EXPERIMENTAL
-+ help
-+ Select this if you want to boot the kernel inside qemu-fast,
-+ the non-mmu version of the x86 emulator. See
-+ <http://fabrice.bellard.free.fr/qemu/>. Say N.
-+
- #
- # Define implied options from the CPU selection here
- #
---- linux-2.6.9/include/asm-i386/fixmap.h 2004-10-18 23:53:08.000000000 +0200
-+++ linux-2.6.9-qemu/include/asm-i386/fixmap.h 2004-12-07 23:16:11.000000000 +0100
-@@ -20,7 +20,11 @@
- * Leave one empty page between vmalloc'ed areas and
- * the start of the fixmap.
- */
-+#ifdef CONFIG_QEMU
-+#define __FIXADDR_TOP 0xa7fff000
-+#else
- #define __FIXADDR_TOP 0xfffff000
-+#endif
-
- #ifndef __ASSEMBLY__
- #include <linux/kernel.h>
---- linux-2.6.9/include/asm-i386/page.h 2004-10-18 23:53:22.000000000 +0200
-+++ linux-2.6.9-qemu/include/asm-i386/page.h 2004-12-07 21:56:49.000000000 +0100
-@@ -121,12 +121,19 @@ extern int sysctl_legacy_va_layout;
- #endif /* __ASSEMBLY__ */
-
- #ifdef __ASSEMBLY__
-+#ifdef CONFIG_QEMU
-+#define __PAGE_OFFSET (0x90000000)
-+#else
- #define __PAGE_OFFSET (0xC0000000)
-+#endif /* QEMU */
-+#else
-+#ifdef CONFIG_QEMU
-+#define __PAGE_OFFSET (0x90000000UL)
- #else
- #define __PAGE_OFFSET (0xC0000000UL)
-+#endif /* QEMU */
- #endif
-
--
- #define PAGE_OFFSET ((unsigned long)__PAGE_OFFSET)
- #define VMALLOC_RESERVE ((unsigned long)__VMALLOC_RESERVE)
- #define MAXMEM (-__PAGE_OFFSET-__VMALLOC_RESERVE)
---- linux-2.6.9/include/asm-i386/param.h 2004-10-18 23:53:24.000000000 +0200
-+++ linux-2.6.9-qemu/include/asm-i386/param.h 2004-12-07 21:56:49.000000000 +0100
-@@ -2,7 +2,12 @@
- #define _ASMi386_PARAM_H
-
- #ifdef __KERNEL__
--# define HZ 1000 /* Internal kernel timer frequency */
-+# include <linux/config.h>
-+# ifdef CONFIG_QEMU
-+# define HZ 100
-+# else
-+# define HZ 1000 /* Internal kernel timer frequency */
-+# endif
- # define USER_HZ 100 /* .. some user interfaces are in "ticks" */
- # define CLOCKS_PER_SEC (USER_HZ) /* like times() */
- #endif
Added: trunk/src/host/qemu-neo1973/linux-user/alpha/syscall.h
===================================================================
--- trunk/src/host/qemu-neo1973/linux-user/alpha/syscall.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/linux-user/alpha/syscall.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,115 @@
+/* default linux values for the selectors */
+#define __USER_DS (1)
+
+struct target_pt_regs {
+ target_ulong r0;
+ target_ulong r1;
+ target_ulong r2;
+ target_ulong r3;
+ target_ulong r4;
+ target_ulong r5;
+ target_ulong r6;
+ target_ulong r7;
+ target_ulong r8;
+ target_ulong r19;
+ target_ulong r20;
+ target_ulong r21;
+ target_ulong r22;
+ target_ulong r23;
+ target_ulong r24;
+ target_ulong r25;
+ target_ulong r26;
+ target_ulong r27;
+ target_ulong r28;
+ target_ulong hae;
+/* JRP - These are the values provided to a0-a2 by PALcode */
+ target_ulong trap_a0;
+ target_ulong trap_a1;
+ target_ulong trap_a2;
+/* These are saved by PAL-code: */
+ target_ulong ps;
+ target_ulong pc;
+ target_ulong gp;
+ target_ulong r16;
+ target_ulong r17;
+ target_ulong r18;
+/* Those is needed by qemu to temporary store the user stack pointer */
+ target_ulong usp;
+ target_ulong unique;
+};
+
+#define TARGET_SEMOP 1
+#define TARGET_SEMGET 2
+#define TARGET_SEMCTL 3
+#define TARGET_MSGSND 11
+#define TARGET_MSGRCV 12
+#define TARGET_MSGGET 13
+#define TARGET_MSGCTL 14
+#define TARGET_SHMAT 21
+#define TARGET_SHMDT 22
+#define TARGET_SHMGET 23
+#define TARGET_SHMCTL 24
+
+struct target_msgbuf {
+ int mtype;
+ char mtext[1];
+};
+
+struct target_ipc_kludge {
+ unsigned int msgp; /* Really (struct msgbuf *) */
+ int msgtyp;
+};
+
+struct target_ipc_perm {
+ int key;
+ unsigned short uid;
+ unsigned short gid;
+ unsigned short cuid;
+ unsigned short cgid;
+ unsigned short mode;
+ unsigned short seq;
+};
+
+struct target_msqid_ds {
+ struct target_ipc_perm msg_perm;
+ unsigned int msg_first; /* really struct target_msg* */
+ unsigned int msg_last; /* really struct target_msg* */
+ unsigned int msg_stime; /* really target_time_t */
+ unsigned int msg_rtime; /* really target_time_t */
+ unsigned int msg_ctime; /* really target_time_t */
+ unsigned int wwait; /* really struct wait_queue* */
+ unsigned int rwait; /* really struct wait_queue* */
+ unsigned short msg_cbytes;
+ unsigned short msg_qnum;
+ unsigned short msg_qbytes;
+ unsigned short msg_lspid;
+ unsigned short msg_lrpid;
+};
+
+struct target_shmid_ds {
+ struct target_ipc_perm shm_perm;
+ int shm_segsz;
+ unsigned int shm_atime; /* really target_time_t */
+ unsigned int shm_dtime; /* really target_time_t */
+ unsigned int shm_ctime; /* really target_time_t */
+ unsigned short shm_cpid;
+ unsigned short shm_lpid;
+ short shm_nattch;
+ unsigned short shm_npages;
+ unsigned long *shm_pages;
+ void *attaches; /* really struct shm_desc * */
+};
+
+#define TARGET_IPC_RMID 0
+#define TARGET_IPC_SET 1
+#define TARGET_IPC_STAT 2
+
+union target_semun {
+ int val;
+ unsigned int buf; /* really struct semid_ds * */
+ unsigned int array; /* really unsigned short * */
+ unsigned int __buf; /* really struct seminfo * */
+ unsigned int __pad; /* really void* */
+};
+
+#define UNAME_MACHINE "alpha"
Added: trunk/src/host/qemu-neo1973/linux-user/alpha/syscall_nr.h
===================================================================
--- trunk/src/host/qemu-neo1973/linux-user/alpha/syscall_nr.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/linux-user/alpha/syscall_nr.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,381 @@
+#define TARGET_NR_osf_syscall 0 /* not implemented */
+#define TARGET_NR_exit 1
+#define TARGET_NR_fork 2
+#define TARGET_NR_read 3
+#define TARGET_NR_write 4
+#define TARGET_NR_osf_old_open 5 /* not implemented */
+#define TARGET_NR_close 6
+#define TARGET_NR_osf_wait4 7
+#define TARGET_NR_osf_old_creat 8 /* not implemented */
+#define TARGET_NR_link 9
+#define TARGET_NR_unlink 10
+#define TARGET_NR_osf_execve 11 /* not implemented */
+#define TARGET_NR_chdir 12
+#define TARGET_NR_fchdir 13
+#define TARGET_NR_mknod 14
+#define TARGET_NR_chmod 15
+#define TARGET_NR_chown 16
+#define TARGET_NR_brk 17
+#define TARGET_NR_osf_getfsstat 18 /* not implemented */
+#define TARGET_NR_lseek 19
+#define TARGET_NR_getxpid 20
+#define TARGET_NR_osf_mount 21
+#define TARGET_NR_umount 22
+#define TARGET_NR_setuid 23
+#define TARGET_NR_getxuid 24
+#define TARGET_NR_exec_with_loader 25 /* not implemented */
+#define TARGET_NR_ptrace 26
+#define TARGET_NR_osf_nrecvmsg 27 /* not implemented */
+#define TARGET_NR_osf_nsendmsg 28 /* not implemented */
+#define TARGET_NR_osf_nrecvfrom 29 /* not implemented */
+#define TARGET_NR_osf_naccept 30 /* not implemented */
+#define TARGET_NR_osf_ngetpeername 31 /* not implemented */
+#define TARGET_NR_osf_ngetsockname 32 /* not implemented */
+#define TARGET_NR_access 33
+#define TARGET_NR_osf_chflags 34 /* not implemented */
+#define TARGET_NR_osf_fchflags 35 /* not implemented */
+#define TARGET_NR_sync 36
+#define TARGET_NR_kill 37
+#define TARGET_NR_osf_old_stat 38 /* not implemented */
+#define TARGET_NR_setpgid 39
+#define TARGET_NR_osf_old_lstat 40 /* not implemented */
+#define TARGET_NR_dup 41
+#define TARGET_NR_pipe 42
+#define TARGET_NR_osf_set_program_attributes 43
+#define TARGET_NR_osf_profil 44 /* not implemented */
+#define TARGET_NR_open 45
+#define TARGET_NR_osf_old_sigaction 46 /* not implemented */
+#define TARGET_NR_getxgid 47
+#define TARGET_NR_osf_sigprocmask 48
+#define TARGET_NR_osf_getlogin 49 /* not implemented */
+#define TARGET_NR_osf_setlogin 50 /* not implemented */
+#define TARGET_NR_acct 51
+#define TARGET_NR_sigpending 52
+
+#define TARGET_NR_ioctl 54
+#define TARGET_NR_osf_reboot 55 /* not implemented */
+#define TARGET_NR_osf_revoke 56 /* not implemented */
+#define TARGET_NR_symlink 57
+#define TARGET_NR_readlink 58
+#define TARGET_NR_execve 59
+#define TARGET_NR_umask 60
+#define TARGET_NR_chroot 61
+#define TARGET_NR_osf_old_fstat 62 /* not implemented */
+#define TARGET_NR_getpgrp 63
+#define TARGET_NR_getpagesize 64
+#define TARGET_NR_osf_mremap 65 /* not implemented */
+#define TARGET_NR_vfork 66
+#define TARGET_NR_stat 67
+#define TARGET_NR_lstat 68
+#define TARGET_NR_osf_sbrk 69 /* not implemented */
+#define TARGET_NR_osf_sstk 70 /* not implemented */
+#define TARGET_NR_mmap 71 /* OSF/1 mmap is superset of Linux */
+#define TARGET_NR_osf_old_vadvise 72 /* not implemented */
+#define TARGET_NR_munmap 73
+#define TARGET_NR_mprotect 74
+#define TARGET_NR_madvise 75
+#define TARGET_NR_vhangup 76
+#define TARGET_NR_osf_kmodcall 77 /* not implemented */
+#define TARGET_NR_osf_mincore 78 /* not implemented */
+#define TARGET_NR_getgroups 79
+#define TARGET_NR_setgroups 80
+#define TARGET_NR_osf_old_getpgrp 81 /* not implemented */
+#define TARGET_NR_setpgrp 82 /* BSD alias for setpgid */
+#define TARGET_NR_osf_setitimer 83
+#define TARGET_NR_osf_old_wait 84 /* not implemented */
+#define TARGET_NR_osf_table 85 /* not implemented */
+#define TARGET_NR_osf_getitimer 86
+#define TARGET_NR_gethostname 87
+#define TARGET_NR_sethostname 88
+#define TARGET_NR_getdtablesize 89
+#define TARGET_NR_dup2 90
+#define TARGET_NR_fstat 91
+#define TARGET_NR_fcntl 92
+#define TARGET_NR_osf_select 93
+#define TARGET_NR_poll 94
+#define TARGET_NR_fsync 95
+#define TARGET_NR_setpriority 96
+#define TARGET_NR_socket 97
+#define TARGET_NR_connect 98
+#define TARGET_NR_accept 99
+#define TARGET_NR_getpriority 100
+#define TARGET_NR_send 101
+#define TARGET_NR_recv 102
+#define TARGET_NR_sigreturn 103
+#define TARGET_NR_bind 104
+#define TARGET_NR_setsockopt 105
+#define TARGET_NR_listen 106
+#define TARGET_NR_osf_plock 107 /* not implemented */
+#define TARGET_NR_osf_old_sigvec 108 /* not implemented */
+#define TARGET_NR_osf_old_sigblock 109 /* not implemented */
+#define TARGET_NR_osf_old_sigsetmask 110 /* not implemented */
+#define TARGET_NR_sigsuspend 111
+#define TARGET_NR_osf_sigstack 112
+#define TARGET_NR_recvmsg 113
+#define TARGET_NR_sendmsg 114
+#define TARGET_NR_osf_old_vtrace 115 /* not implemented */
+#define TARGET_NR_osf_gettimeofday 116
+#define TARGET_NR_osf_getrusage 117
+#define TARGET_NR_getsockopt 118
+
+#define TARGET_NR_readv 120
+#define TARGET_NR_writev 121
+#define TARGET_NR_osf_settimeofday 122
+#define TARGET_NR_fchown 123
+#define TARGET_NR_fchmod 124
+#define TARGET_NR_recvfrom 125
+#define TARGET_NR_setreuid 126
+#define TARGET_NR_setregid 127
+#define TARGET_NR_rename 128
+#define TARGET_NR_truncate 129
+#define TARGET_NR_ftruncate 130
+#define TARGET_NR_flock 131
+#define TARGET_NR_setgid 132
+#define TARGET_NR_sendto 133
+#define TARGET_NR_shutdown 134
+#define TARGET_NR_socketpair 135
+#define TARGET_NR_mkdir 136
+#define TARGET_NR_rmdir 137
+#define TARGET_NR_osf_utimes 138
+#define TARGET_NR_osf_old_sigreturn 139 /* not implemented */
+#define TARGET_NR_osf_adjtime 140 /* not implemented */
+#define TARGET_NR_getpeername 141
+#define TARGET_NR_osf_gethostid 142 /* not implemented */
+#define TARGET_NR_osf_sethostid 143 /* not implemented */
+#define TARGET_NR_getrlimit 144
+#define TARGET_NR_setrlimit 145
+#define TARGET_NR_osf_old_killpg 146 /* not implemented */
+#define TARGET_NR_setsid 147
+#define TARGET_NR_quotactl 148
+#define TARGET_NR_osf_oldquota 149 /* not implemented */
+#define TARGET_NR_getsockname 150
+
+#define TARGET_NR_osf_pid_block 153 /* not implemented */
+#define TARGET_NR_osf_pid_unblock 154 /* not implemented */
+
+#define TARGET_NR_sigaction 156
+#define TARGET_NR_osf_sigwaitprim 157 /* not implemented */
+#define TARGET_NR_osf_nfssvc 158 /* not implemented */
+#define TARGET_NR_osf_getdirentries 159
+#define TARGET_NR_osf_statfs 160
+#define TARGET_NR_osf_fstatfs 161
+
+#define TARGET_NR_osf_asynch_daemon 163 /* not implemented */
+#define TARGET_NR_osf_getfh 164 /* not implemented */
+#define TARGET_NR_osf_getdomainname 165
+#define TARGET_NR_setdomainname 166
+
+#define TARGET_NR_osf_exportfs 169 /* not implemented */
+
+#define TARGET_NR_osf_alt_plock 181 /* not implemented */
+
+#define TARGET_NR_osf_getmnt 184 /* not implemented */
+
+#define TARGET_NR_osf_alt_sigpending 187 /* not implemented */
+#define TARGET_NR_osf_alt_setsid 188 /* not implemented */
+
+#define TARGET_NR_osf_swapon 199
+#define TARGET_NR_msgctl 200
+#define TARGET_NR_msgget 201
+#define TARGET_NR_msgrcv 202
+#define TARGET_NR_msgsnd 203
+#define TARGET_NR_semctl 204
+#define TARGET_NR_semget 205
+#define TARGET_NR_semop 206
+#define TARGET_NR_osf_utsname 207
+#define TARGET_NR_lchown 208
+#define TARGET_NR_osf_shmat 209
+#define TARGET_NR_shmctl 210
+#define TARGET_NR_shmdt 211
+#define TARGET_NR_shmget 212
+#define TARGET_NR_osf_mvalid 213 /* not implemented */
+#define TARGET_NR_osf_getaddressconf 214 /* not implemented */
+#define TARGET_NR_osf_msleep 215 /* not implemented */
+#define TARGET_NR_osf_mwakeup 216 /* not implemented */
+#define TARGET_NR_msync 217
+#define TARGET_NR_osf_signal 218 /* not implemented */
+#define TARGET_NR_osf_utc_gettime 219 /* not implemented */
+#define TARGET_NR_osf_utc_adjtime 220 /* not implemented */
+
+#define TARGET_NR_osf_security 222 /* not implemented */
+#define TARGET_NR_osf_kloadcall 223 /* not implemented */
+
+#define TARGET_NR_getpgid 233
+#define TARGET_NR_getsid 234
+#define TARGET_NR_sigaltstack 235
+#define TARGET_NR_osf_waitid 236 /* not implemented */
+#define TARGET_NR_osf_priocntlset 237 /* not implemented */
+#define TARGET_NR_osf_sigsendset 238 /* not implemented */
+#define TARGET_NR_osf_set_speculative 239 /* not implemented */
+#define TARGET_NR_osf_msfs_syscall 240 /* not implemented */
+#define TARGET_NR_osf_sysinfo 241
+#define TARGET_NR_osf_uadmin 242 /* not implemented */
+#define TARGET_NR_osf_fuser 243 /* not implemented */
+#define TARGET_NR_osf_proplist_syscall 244
+#define TARGET_NR_osf_ntp_adjtime 245 /* not implemented */
+#define TARGET_NR_osf_ntp_gettime 246 /* not implemented */
+#define TARGET_NR_osf_pathconf 247 /* not implemented */
+#define TARGET_NR_osf_fpathconf 248 /* not implemented */
+
+#define TARGET_NR_osf_uswitch 250 /* not implemented */
+#define TARGET_NR_osf_usleep_thread 251
+#define TARGET_NR_osf_audcntl 252 /* not implemented */
+#define TARGET_NR_osf_audgen 253 /* not implemented */
+#define TARGET_NR_sysfs 254
+#define TARGET_NR_osf_subsys_info 255 /* not implemented */
+#define TARGET_NR_osf_getsysinfo 256
+#define TARGET_NR_osf_setsysinfo 257
+#define TARGET_NR_osf_afs_syscall 258 /* not implemented */
+#define TARGET_NR_osf_swapctl 259 /* not implemented */
+#define TARGET_NR_osf_memcntl 260 /* not implemented */
+#define TARGET_NR_osf_fdatasync 261 /* not implemented */
+
+
+/*
+ * Linux-specific system calls begin at 300
+ */
+#define TARGET_NR_bdflush 300
+#define TARGET_NR_sethae 301
+#define TARGET_NR_mount 302
+#define TARGET_NR_old_adjtimex 303
+#define TARGET_NR_swapoff 304
+#define TARGET_NR_getdents 305
+#define TARGET_NR_create_module 306
+#define TARGET_NR_init_module 307
+#define TARGET_NR_delete_module 308
+#define TARGET_NR_get_kernel_syms 309
+#define TARGET_NR_syslog 310
+#define TARGET_NR_reboot 311
+#define TARGET_NR_clone 312
+#define TARGET_NR_uselib 313
+#define TARGET_NR_mlock 314
+#define TARGET_NR_munlock 315
+#define TARGET_NR_mlockall 316
+#define TARGET_NR_munlockall 317
+#define TARGET_NR_sysinfo 318
+#define TARGET_NR__sysctl 319
+/* 320 was sys_idle. */
+#define TARGET_NR_oldumount 321
+#define TARGET_NR_swapon 322
+#define TARGET_NR_times 323
+#define TARGET_NR_personality 324
+#define TARGET_NR_setfsuid 325
+#define TARGET_NR_setfsgid 326
+#define TARGET_NR_ustat 327
+#define TARGET_NR_statfs 328
+#define TARGET_NR_fstatfs 329
+#define TARGET_NR_sched_setparam 330
+#define TARGET_NR_sched_getparam 331
+#define TARGET_NR_sched_setscheduler 332
+#define TARGET_NR_sched_getscheduler 333
+#define TARGET_NR_sched_yield 334
+#define TARGET_NR_sched_get_priority_max 335
+#define TARGET_NR_sched_get_priority_min 336
+#define TARGET_NR_sched_rr_get_interval 337
+#define TARGET_NR_afs_syscall 338
+#define TARGET_NR_uname 339
+#define TARGET_NR_nanosleep 340
+#define TARGET_NR_mremap 341
+#define TARGET_NR_nfsservctl 342
+#define TARGET_NR_setresuid 343
+#define TARGET_NR_getresuid 344
+#define TARGET_NR_pciconfig_read 345
+#define TARGET_NR_pciconfig_write 346
+#define TARGET_NR_query_module 347
+#define TARGET_NR_prctl 348
+#define TARGET_NR_pread64 349
+#define TARGET_NR_pwrite64 350
+#define TARGET_NR_rt_sigreturn 351
+#define TARGET_NR_rt_sigaction 352
+#define TARGET_NR_rt_sigprocmask 353
+#define TARGET_NR_rt_sigpending 354
+#define TARGET_NR_rt_sigtimedwait 355
+#define TARGET_NR_rt_sigqueueinfo 356
+#define TARGET_NR_rt_sigsuspend 357
+#define TARGET_NR_select 358
+#define TARGET_NR_gettimeofday 359
+#define TARGET_NR_settimeofday 360
+#define TARGET_NR_getitimer 361
+#define TARGET_NR_setitimer 362
+#define TARGET_NR_utimes 363
+#define TARGET_NR_getrusage 364
+#define TARGET_NR_wait4 365
+#define TARGET_NR_adjtimex 366
+#define TARGET_NR_getcwd 367
+#define TARGET_NR_capget 368
+#define TARGET_NR_capset 369
+#define TARGET_NR_sendfile 370
+#define TARGET_NR_setresgid 371
+#define TARGET_NR_getresgid 372
+#define TARGET_NR_dipc 373
+#define TARGET_NR_pivot_root 374
+#define TARGET_NR_mincore 375
+#define TARGET_NR_pciconfig_iobase 376
+#define TARGET_NR_getdents64 377
+#define TARGET_NR_gettid 378
+#define TARGET_NR_readahead 379
+/* 380 is unused */
+#define TARGET_NR_tkill 381
+#define TARGET_NR_setxattr 382
+#define TARGET_NR_lsetxattr 383
+#define TARGET_NR_fsetxattr 384
+#define TARGET_NR_getxattr 385
+#define TARGET_NR_lgetxattr 386
+#define TARGET_NR_fgetxattr 387
+#define TARGET_NR_listxattr 388
+#define TARGET_NR_llistxattr 389
+#define TARGET_NR_flistxattr 390
+#define TARGET_NR_removexattr 391
+#define TARGET_NR_lremovexattr 392
+#define TARGET_NR_fremovexattr 393
+#define TARGET_NR_futex 394
+#define TARGET_NR_sched_setaffinity 395
+#define TARGET_NR_sched_getaffinity 396
+#define TARGET_NR_tuxcall 397
+#define TARGET_NR_io_setup 398
+#define TARGET_NR_io_destroy 399
+#define TARGET_NR_io_getevents 400
+#define TARGET_NR_io_submit 401
+#define TARGET_NR_io_cancel 402
+#define TARGET_NR_exit_group 405
+#define TARGET_NR_lookup_dcookie 406
+#define TARGET_NR_sys_epoll_create 407
+#define TARGET_NR_sys_epoll_ctl 408
+#define TARGET_NR_sys_epoll_wait 409
+#define TARGET_NR_remap_file_pages 410
+#define TARGET_NR_set_tid_address 411
+#define TARGET_NR_restart_syscall 412
+#define TARGET_NR_fadvise64 413
+#define TARGET_NR_timer_create 414
+#define TARGET_NR_timer_settime 415
+#define TARGET_NR_timer_gettime 416
+#define TARGET_NR_timer_getoverrun 417
+#define TARGET_NR_timer_delete 418
+#define TARGET_NR_clock_settime 419
+#define TARGET_NR_clock_gettime 420
+#define TARGET_NR_clock_getres 421
+#define TARGET_NR_clock_nanosleep 422
+#define TARGET_NR_semtimedop 423
+#define TARGET_NR_tgkill 424
+#define TARGET_NR_stat64 425
+#define TARGET_NR_lstat64 426
+#define TARGET_NR_fstat64 427
+#define TARGET_NR_vserver 428
+#define TARGET_NR_mbind 429
+#define TARGET_NR_get_mempolicy 430
+#define TARGET_NR_set_mempolicy 431
+#define TARGET_NR_mq_open 432
+#define TARGET_NR_mq_unlink 433
+#define TARGET_NR_mq_timedsend 434
+#define TARGET_NR_mq_timedreceive 435
+#define TARGET_NR_mq_notify 436
+#define TARGET_NR_mq_getsetattr 437
+#define TARGET_NR_waitid 438
+#define TARGET_NR_add_key 439
+#define TARGET_NR_request_key 440
+#define TARGET_NR_keyctl 441
+#define TARGET_NR_ioprio_set 442
+#define TARGET_NR_ioprio_get 443
+#define TARGET_NR_inotify_init 444
+#define TARGET_NR_inotify_add_watch 445
+#define TARGET_NR_inotify_rm_watch 446
Added: trunk/src/host/qemu-neo1973/linux-user/alpha/termbits.h
===================================================================
--- trunk/src/host/qemu-neo1973/linux-user/alpha/termbits.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/linux-user/alpha/termbits.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,265 @@
+typedef unsigned char cc_t;
+typedef unsigned int speed_t;
+typedef unsigned int tcflag_t;
+
+#define TARGET_NCCS 19
+struct target_termios {
+ tcflag_t c_iflag; /* input mode flags */
+ tcflag_t c_oflag; /* output mode flags */
+ tcflag_t c_cflag; /* control mode flags */
+ tcflag_t c_lflag; /* local mode flags */
+ cc_t c_cc[TARGET_NCCS]; /* control characters */
+ cc_t c_line; /* line discipline (== c_cc[19]) */
+ speed_t c_ispeed; /* input speed */
+ speed_t c_ospeed; /* output speed */
+};
+
+/* c_cc characters */
+#define TARGET_VEOF 0
+#define TARGET_VEOL 1
+#define TARGET_VEOL2 2
+#define TARGET_VERASE 3
+#define TARGET_VWERASE 4
+#define TARGET_VKILL 5
+#define TARGET_VREPRINT 6
+#define TARGET_VSWTC 7
+#define TARGET_VINTR 8
+#define TARGET_VQUIT 9
+#define TARGET_VSUSP 10
+#define TARGET_VSTART 12
+#define TARGET_VSTOP 13
+#define TARGET_VLNEXT 14
+#define TARGET_VDISCARD 15
+#define TARGET_VMIN 16
+#define TARGET_VTIME 17
+
+/* c_iflag bits */
+#define TARGET_IGNBRK 0000001
+#define TARGET_BRKINT 0000002
+#define TARGET_IGNPAR 0000004
+#define TARGET_PARMRK 0000010
+#define TARGET_INPCK 0000020
+#define TARGET_ISTRIP 0000040
+#define TARGET_INLCR 0000100
+#define TARGET_IGNCR 0000200
+#define TARGET_ICRNL 0000400
+#define TARGET_IXON 0001000
+#define TARGET_IXOFF 0002000
+#define TARGET_IXANY 0004000
+#define TARGET_IUCLC 0010000
+#define TARGET_IMAXBEL 0020000
+#define TARGET_IUTF8 0040000
+
+/* c_oflag bits */
+#define TARGET_OPOST 0000001
+#define TARGET_ONLCR 0000002
+#define TARGET_OLCUC 0000004
+
+#define TARGET_OCRNL 0000010
+#define TARGET_ONOCR 0000020
+#define TARGET_ONLRET 0000040
+
+#define TARGET_OFILL 00000100
+#define TARGET_OFDEL 00000200
+#define TARGET_NLDLY 00001400
+#define TARGET_NL0 00000000
+#define TARGET_NL1 00000400
+#define TARGET_NL2 00001000
+#define TARGET_NL3 00001400
+#define TARGET_TABDLY 00006000
+#define TARGET_TAB0 00000000
+#define TARGET_TAB1 00002000
+#define TARGET_TAB2 00004000
+#define TARGET_TAB3 00006000
+#define TARGET_CRDLY 00030000
+#define TARGET_CR0 00000000
+#define TARGET_CR1 00010000
+#define TARGET_CR2 00020000
+#define TARGET_CR3 00030000
+#define TARGET_FFDLY 00040000
+#define TARGET_FF0 00000000
+#define TARGET_FF1 00040000
+#define TARGET_BSDLY 00100000
+#define TARGET_BS0 00000000
+#define TARGET_BS1 00100000
+#define TARGET_VTDLY 00200000
+#define TARGET_VT0 00000000
+#define TARGET_VT1 00200000
+#define TARGET_XTABS 01000000 /* Hmm.. Linux/i386 considers this part of TABDLY.. */
+
+/* c_cflag bit meaning */
+#define TARGET_CBAUD 0000037
+#define TARGET_B0 0000000 /* hang up */
+#define TARGET_B50 0000001
+#define TARGET_B75 0000002
+#define TARGET_B110 0000003
+#define TARGET_B134 0000004
+#define TARGET_B150 0000005
+#define TARGET_B200 0000006
+#define TARGET_B300 0000007
+#define TARGET_B600 0000010
+#define TARGET_B1200 0000011
+#define TARGET_B1800 0000012
+#define TARGET_B2400 0000013
+#define TARGET_B4800 0000014
+#define TARGET_B9600 0000015
+#define TARGET_B19200 0000016
+#define TARGET_B38400 0000017
+#define TARGET_EXTA B19200
+#define TARGET_EXTB B38400
+#define TARGET_CBAUDEX 0000000
+#define TARGET_B57600 00020
+#define TARGET_B115200 00021
+#define TARGET_B230400 00022
+#define TARGET_B460800 00023
+#define TARGET_B500000 00024
+#define TARGET_B576000 00025
+#define TARGET_B921600 00026
+#define TARGET_B1000000 00027
+#define TARGET_B1152000 00030
+#define TARGET_B1500000 00031
+#define TARGET_B2000000 00032
+#define TARGET_B2500000 00033
+#define TARGET_B3000000 00034
+#define TARGET_B3500000 00035
+#define TARGET_B4000000 00036
+
+#define TARGET_CSIZE 00001400
+#define TARGET_CS5 00000000
+#define TARGET_CS6 00000400
+#define TARGET_CS7 00001000
+#define TARGET_CS8 00001400
+
+#define TARGET_CSTOPB 00002000
+#define TARGET_CREAD 00004000
+#define TARGET_PARENB 00010000
+#define TARGET_PARODD 00020000
+#define TARGET_HUPCL 00040000
+
+#define TARGET_CLOCAL 00100000
+#define TARGET_CMSPAR 010000000000 /* mark or space (stick) parity */
+#define TARGET_CRTSCTS 020000000000 /* flow control */
+
+/* c_lflag bits */
+#define TARGET_ISIG 0x00000080
+#define TARGET_ICANON 0x00000100
+#define TARGET_XCASE 0x00004000
+#define TARGET_ECHO 0x00000008
+#define TARGET_ECHOE 0x00000002
+#define TARGET_ECHOK 0x00000004
+#define TARGET_ECHONL 0x00000010
+#define TARGET_NOFLSH 0x80000000
+#define TARGET_TOSTOP 0x00400000
+#define TARGET_ECHOCTL 0x00000040
+#define TARGET_ECHOPRT 0x00000020
+#define TARGET_ECHOKE 0x00000001
+#define TARGET_FLUSHO 0x00800000
+#define TARGET_PENDIN 0x20000000
+#define TARGET_IEXTEN 0x00000400
+
+#define TARGET_FIOCLEX _IO('f', 1)
+#define TARGET_FIONCLEX _IO('f', 2)
+#define TARGET_FIOASYNC _IOW('f', 125, int)
+#define TARGET_FIONBIO _IOW('f', 126, int)
+#define TARGET_FIONREAD _IOR('f', 127, int)
+#define TARGET_TIOCINQ FIONREAD
+#define TARGET_FIOQSIZE _IOR('f', 128, loff_t)
+
+#define TARGET_TIOCGETP _IOR('t', 8, struct sgttyb)
+#define TARGET_TIOCSETP _IOW('t', 9, struct sgttyb)
+#define TARGET_TIOCSETN _IOW('t', 10, struct sgttyb) /* TIOCSETP wo flush */
+
+#define TARGET_TIOCSETC _IOW('t', 17, struct tchars)
+#define TARGET_TIOCGETC _IOR('t', 18, struct tchars)
+#define TARGET_TCGETS _IOR('t', 19, struct termios)
+#define TARGET_TCSETS _IOW('t', 20, struct termios)
+#define TARGET_TCSETSW _IOW('t', 21, struct termios)
+#define TARGET_TCSETSF _IOW('t', 22, struct termios)
+
+#define TARGET_TCGETA _IOR('t', 23, struct termio)
+#define TARGET_TCSETA _IOW('t', 24, struct termio)
+#define TARGET_TCSETAW _IOW('t', 25, struct termio)
+#define TARGET_TCSETAF _IOW('t', 28, struct termio)
+
+#define TARGET_TCSBRK _IO('t', 29)
+#define TARGET_TCXONC _IO('t', 30)
+#define TARGET_TCFLSH _IO('t', 31)
+
+#define TARGET_TIOCSWINSZ _IOW('t', 103, struct winsize)
+#define TARGET_TIOCGWINSZ _IOR('t', 104, struct winsize)
+#define TARGET_TIOCSTART _IO('t', 110) /* start output, like ^Q */
+#define TARGET_TIOCSTOP _IO('t', 111) /* stop output, like ^S */
+#define TARGET_TIOCOUTQ _IOR('t', 115, int) /* output queue size */
+
+#define TARGET_TIOCGLTC _IOR('t', 116, struct ltchars)
+#define TARGET_TIOCSLTC _IOW('t', 117, struct ltchars)
+#define TARGET_TIOCSPGRP _IOW('t', 118, int)
+#define TARGET_TIOCGPGRP _IOR('t', 119, int)
+
+#define TARGET_TIOCEXCL 0x540C
+#define TARGET_TIOCNXCL 0x540D
+#define TARGET_TIOCSCTTY 0x540E
+
+#define TARGET_TIOCSTI 0x5412
+#define TARGET_TIOCMGET 0x5415
+#define TARGET_TIOCMBIS 0x5416
+#define TARGET_TIOCMBIC 0x5417
+#define TARGET_TIOCMSET 0x5418
+# define TARGET_TIOCM_LE 0x001
+# define TARGET_TIOCM_DTR 0x002
+# define TARGET_TIOCM_RTS 0x004
+# define TARGET_TIOCM_ST 0x008
+# define TARGET_TIOCM_SR 0x010
+# define TARGET_TIOCM_CTS 0x020
+# define TARGET_TIOCM_CAR 0x040
+# define TARGET_TIOCM_RNG 0x080
+# define TARGET_TIOCM_DSR 0x100
+# define TARGET_TIOCM_CD TIOCM_CAR
+# define TARGET_TIOCM_RI TIOCM_RNG
+# define TARGET_TIOCM_OUT1 0x2000
+# define TARGET_TIOCM_OUT2 0x4000
+# define TARGET_TIOCM_LOOP 0x8000
+
+#define TARGET_TIOCGSOFTCAR 0x5419
+#define TARGET_TIOCSSOFTCAR 0x541A
+#define TARGET_TIOCLINUX 0x541C
+#define TARGET_TIOCCONS 0x541D
+#define TARGET_TIOCGSERIAL 0x541E
+#define TARGET_TIOCSSERIAL 0x541F
+#define TARGET_TIOCPKT 0x5420
+# define TARGET_TIOCPKT_DATA 0
+# define TARGET_TIOCPKT_FLUSHREAD 1
+# define TARGET_TIOCPKT_FLUSHWRITE 2
+# define TARGET_TIOCPKT_STOP 4
+# define TARGET_TIOCPKT_START 8
+# define TARGET_TIOCPKT_NOSTOP 16
+# define TARGET_TIOCPKT_DOSTOP 32
+
+
+#define TARGET_TIOCNOTTY 0x5422
+#define TARGET_TIOCSETD 0x5423
+#define TARGET_TIOCGETD 0x5424
+#define TARGET_TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */
+#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */
+#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */
+#define TARGET_TIOCGSID 0x5429 /* Return the session ID of FD */
+#define TARGET_TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
+#define TARGET_TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */
+
+#define TARGET_TIOCSERCONFIG 0x5453
+#define TARGET_TIOCSERGWILD 0x5454
+#define TARGET_TIOCSERSWILD 0x5455
+#define TARGET_TIOCGLCKTRMIOS 0x5456
+#define TARGET_TIOCSLCKTRMIOS 0x5457
+#define TARGET_TIOCSERGSTRUCT 0x5458 /* For debugging only */
+#define TARGET_TIOCSERGETLSR 0x5459 /* Get line status register */
+ /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
+# define TARGET_TIOCSER_TEMT 0x01 /* Transmitter physically empty */
+#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config */
+#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */
+
+#define TARGET_TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */
+#define TARGET_TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */
+#define TARGET_TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */
+#define TARGET_TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */
+
Deleted: trunk/src/host/qemu-neo1973/linux-user/arm-semi.c
===================================================================
--- trunk/src/host/qemu-neo1973/linux-user/arm-semi.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/linux-user/arm-semi.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -1,235 +0,0 @@
-/*
- * Arm "Angel" semihosting syscalls
- *
- * Copyright (c) 2005 CodeSourcery, LLC. Written by Paul Brook.
- *
- * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <time.h>
-
-#include "qemu.h"
-
-#define ARM_ANGEL_HEAP_SIZE (128 * 1024 * 1024)
-
-#define SYS_OPEN 0x01
-#define SYS_CLOSE 0x02
-#define SYS_WRITEC 0x03
-#define SYS_WRITE0 0x04
-#define SYS_WRITE 0x05
-#define SYS_READ 0x06
-#define SYS_READC 0x07
-#define SYS_ISTTY 0x09
-#define SYS_SEEK 0x0a
-#define SYS_FLEN 0x0c
-#define SYS_TMPNAM 0x0d
-#define SYS_REMOVE 0x0e
-#define SYS_RENAME 0x0f
-#define SYS_CLOCK 0x10
-#define SYS_TIME 0x11
-#define SYS_SYSTEM 0x12
-#define SYS_ERRNO 0x13
-#define SYS_GET_CMDLINE 0x15
-#define SYS_HEAPINFO 0x16
-#define SYS_EXIT 0x18
-
-#ifndef O_BINARY
-#define O_BINARY 0
-#endif
-
-int open_modeflags[12] = {
- O_RDONLY,
- O_RDONLY | O_BINARY,
- O_RDWR,
- O_RDWR | O_BINARY,
- O_WRONLY | O_CREAT | O_TRUNC,
- O_WRONLY | O_CREAT | O_TRUNC | O_BINARY,
- O_RDWR | O_CREAT | O_TRUNC,
- O_RDWR | O_CREAT | O_TRUNC | O_BINARY,
- O_WRONLY | O_CREAT | O_APPEND,
- O_WRONLY | O_CREAT | O_APPEND | O_BINARY,
- O_RDWR | O_CREAT | O_APPEND,
- O_RDWR | O_CREAT | O_APPEND | O_BINARY
-};
-
-static inline uint32_t set_swi_errno(TaskState *ts, uint32_t code)
-{
- if (code == (uint32_t)-1)
- ts->swi_errno = errno;
- return code;
-}
-
-#define ARG(n) tget32(args + (n) * 4)
-#define SET_ARG(n, val) tput32(args + (n) * 4,val)
-uint32_t do_arm_semihosting(CPUState *env)
-{
- target_ulong args;
- char * s;
- int nr;
- uint32_t ret;
- TaskState *ts = env->opaque;
-
- nr = env->regs[0];
- args = env->regs[1];
- switch (nr) {
- case SYS_OPEN:
- s = (char *)g2h(ARG(0));
- if (ARG(1) >= 12)
- return (uint32_t)-1;
- if (strcmp(s, ":tt") == 0) {
- if (ARG(1) < 4)
- return STDIN_FILENO;
- else
- return STDOUT_FILENO;
- }
- return set_swi_errno(ts, open(s, open_modeflags[ARG(1)], 0644));
- case SYS_CLOSE:
- return set_swi_errno(ts, close(ARG(0)));
- case SYS_WRITEC:
- {
- char c = tget8(args);
- /* Write to debug console. stderr is near enough. */
- return write(STDERR_FILENO, &c, 1);
- }
- case SYS_WRITE0:
- s = lock_user_string(args);
- ret = write(STDERR_FILENO, s, strlen(s));
- unlock_user(s, args, 0);
- return ret;
- case SYS_WRITE:
- ret = set_swi_errno(ts, write(ARG(0), g2h(ARG(1)), ARG(2)));
- if (ret == (uint32_t)-1)
- return -1;
- return ARG(2) - ret;
- case SYS_READ:
- ret = set_swi_errno(ts, read(ARG(0), g2h(ARG(1)), ARG(2)));
- if (ret == (uint32_t)-1)
- return -1;
- return ARG(2) - ret;
- case SYS_READC:
- /* XXX: Read from debug cosole. Not implemented. */
- return 0;
- case SYS_ISTTY:
- return isatty(ARG(0));
- case SYS_SEEK:
- ret = set_swi_errno(ts, lseek(ARG(0), ARG(1), SEEK_SET));
- if (ret == (uint32_t)-1)
- return -1;
- return 0;
- case SYS_FLEN:
- {
- struct stat buf;
- ret = set_swi_errno(ts, fstat(ARG(0), &buf));
- if (ret == (uint32_t)-1)
- return -1;
- return buf.st_size;
- }
- case SYS_TMPNAM:
- /* XXX: Not implemented. */
- return -1;
- case SYS_REMOVE:
- return set_swi_errno(ts, remove((char *)g2h(ARG(0))));
- case SYS_RENAME:
- return set_swi_errno(ts, rename((char *)g2h(ARG(0)),
- (char *)g2h(ARG(2))));
- case SYS_CLOCK:
- return clock() / (CLOCKS_PER_SEC / 100);
- case SYS_TIME:
- return set_swi_errno(ts, time(NULL));
- case SYS_SYSTEM:
- return set_swi_errno(ts, system((char *)g2h(ARG(0))));
- case SYS_ERRNO:
- return ts->swi_errno;
- case SYS_GET_CMDLINE:
- /* Build a commandline from the original argv. */
- {
- char **arg = ts->info->host_argv;
- int len = ARG(1);
- /* lock the buffer on the ARM side */
- char *cmdline_buffer = (char*)lock_user(ARG(0), len, 0);
-
- s = cmdline_buffer;
- while (*arg && len > 2) {
- int n = strlen(*arg);
-
- if (s != cmdline_buffer) {
- *(s++) = ' ';
- len--;
- }
- if (n >= len)
- n = len - 1;
- memcpy(s, *arg, n);
- s += n;
- len -= n;
- arg++;
- }
- /* Null terminate the string. */
- *s = 0;
- len = s - cmdline_buffer;
-
- /* Unlock the buffer on the ARM side. */
- unlock_user(cmdline_buffer, ARG(0), len);
-
- /* Adjust the commandline length argument. */
- SET_ARG(1, len);
-
- /* Return success if commandline fit into buffer. */
- return *arg ? -1 : 0;
- }
- case SYS_HEAPINFO:
- {
- uint32_t *ptr;
- uint32_t limit;
-
- /* Some C llibraries assume the heap immediately follows .bss, so
- allocate it using sbrk. */
- if (!ts->heap_limit) {
- long ret;
-
- ts->heap_base = do_brk(0);
- limit = ts->heap_base + ARM_ANGEL_HEAP_SIZE;
- /* Try a big heap, and reduce the size if that fails. */
- for (;;) {
- ret = do_brk(limit);
- if (ret != -1)
- break;
- limit = (ts->heap_base >> 1) + (limit >> 1);
- }
- ts->heap_limit = limit;
- }
-
- page_unprotect_range (ARG(0), 32);
- ptr = (uint32_t *)g2h(ARG(0));
- ptr[0] = tswap32(ts->heap_base);
- ptr[1] = tswap32(ts->heap_limit);
- ptr[2] = tswap32(ts->stack_base);
- ptr[3] = tswap32(0); /* Stack limit. */
- return 0;
- }
- case SYS_EXIT:
- exit(0);
- default:
- fprintf(stderr, "qemu: Unsupported SemiHosting SWI 0x%02x\n", nr);
- cpu_dump_state(env, stderr, fprintf, 0);
- abort();
- }
-}
-
Modified: trunk/src/host/qemu-neo1973/linux-user/elfload.c
===================================================================
--- trunk/src/host/qemu-neo1973/linux-user/elfload.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/linux-user/elfload.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -44,6 +44,23 @@
return global_env->cpuid_features;
}
+#ifdef TARGET_X86_64
+#define ELF_START_MMAP 0x2aaaaab000ULL
+#define elf_check_arch(x) ( ((x) == ELF_ARCH) )
+
+#define ELF_CLASS ELFCLASS64
+#define ELF_DATA ELFDATA2LSB
+#define ELF_ARCH EM_X86_64
+
+static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
+{
+ regs->rax = 0;
+ regs->rsp = infop->start_stack;
+ regs->rip = infop->entry;
+}
+
+#else
+
#define ELF_START_MMAP 0x80000000
/*
@@ -72,6 +89,7 @@
A value of 0 tells we have no such handler. */
regs->edx = 0;
}
+#endif
#define USE_ELF_CORE_DUMP
#define ELF_EXEC_PAGESIZE 4096
@@ -177,9 +195,20 @@
#define ELF_START_MMAP 0x80000000
+#ifdef TARGET_PPC64
+
+#define elf_check_arch(x) ( (x) == EM_PPC64 )
+
+#define ELF_CLASS ELFCLASS64
+
+#else
+
#define elf_check_arch(x) ( (x) == EM_PPC )
#define ELF_CLASS ELFCLASS32
+
+#endif
+
#ifdef TARGET_WORDS_BIGENDIAN
#define ELF_DATA ELFDATA2MSB
#else
@@ -222,9 +251,18 @@
{
target_ulong pos = infop->start_stack;
target_ulong tmp;
+#ifdef TARGET_PPC64
+ target_ulong entry, toc;
+#endif
_regs->msr = 1 << MSR_PR; /* Set user mode */
_regs->gpr[1] = infop->start_stack;
+#ifdef TARGET_PPC64
+ entry = ldq_raw(infop->entry) + infop->load_addr;
+ toc = ldq_raw(infop->entry + 8) + infop->load_addr;
+ _regs->gpr[2] = toc;
+ infop->entry = entry;
+#endif
_regs->nip = infop->entry;
/* Note that isn't exactly what regular kernel does
* but this is what the ABI wants and is needed to allow
@@ -313,6 +351,31 @@
#endif
+#ifdef TARGET_ALPHA
+
+#define ELF_START_MMAP (0x30000000000ULL)
+
+#define elf_check_arch(x) ( (x) == ELF_ARCH )
+
+#define ELF_CLASS ELFCLASS64
+#define ELF_DATA ELFDATA2MSB
+#define ELF_ARCH EM_ALPHA
+
+static inline void init_thread(struct target_pt_regs *regs, struct image_info *infop)
+{
+ regs->pc = infop->entry;
+ regs->ps = 8;
+ regs->usp = infop->start_stack;
+ regs->unique = infop->start_data; /* ? */
+ printf("Set unique value to " TARGET_FMT_lx " (" TARGET_FMT_lx ")\n",
+ regs->unique, infop->start_data);
+}
+
+#define USE_ELF_CORE_DUMP
+#define ELF_EXEC_PAGESIZE 8192
+
+#endif /* TARGET_ALPHA */
+
#ifndef ELF_PLATFORM
#define ELF_PLATFORM (NULL)
#endif
@@ -431,11 +494,11 @@
bswaptls(&shdr->sh_entsize);
}
-static void bswap_sym(Elf32_Sym *sym)
+static void bswap_sym(struct elf_sym *sym)
{
bswap32s(&sym->st_name);
- bswap32s(&sym->st_value);
- bswap32s(&sym->st_size);
+ bswaptls(&sym->st_value);
+ bswaptls(&sym->st_size);
bswap16s(&sym->st_shndx);
}
#endif
@@ -892,6 +955,7 @@
unsigned long elf_entry, interp_load_addr = 0;
int status;
unsigned long start_code, end_code, end_data;
+ unsigned long reloc_func_desc = 0;
unsigned long elf_stack;
char passed_fileno[6];
@@ -1156,6 +1220,7 @@
load_bias += error -
TARGET_ELF_PAGESTART(load_bias + elf_ppnt->p_vaddr);
load_addr += load_bias;
+ reloc_func_desc = load_bias;
}
}
k = elf_ppnt->p_vaddr;
@@ -1188,6 +1253,7 @@
elf_entry = load_elf_interp(&interp_elf_ex, interpreter_fd,
&interp_load_addr);
}
+ reloc_func_desc = interp_load_addr;
close(interpreter_fd);
free(elf_interpreter);
Modified: trunk/src/host/qemu-neo1973/linux-user/flatload.c
===================================================================
--- trunk/src/host/qemu-neo1973/linux-user/flatload.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/linux-user/flatload.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -393,6 +393,7 @@
int i, rev, relocs = 0;
target_ulong fpos;
target_ulong start_code, end_code;
+ target_ulong indx_len;
hdr = ((struct flat_hdr *) bprm->buf); /* exec-header */
@@ -443,6 +444,11 @@
if (extra < bss_len + stack_len)
extra = bss_len + stack_len;
+ /* Add space for library base pointers. Make sure this does not
+ misalign the doesn't misalign the data segment. */
+ indx_len = MAX_SHARED_LIBS * sizeof(target_ulong);
+ indx_len = (indx_len + 15) & ~(target_ulong)15;
+
/*
* there are a couple of cases here, the separate code/data
* case, and then the fully copied to RAM case which lumps
@@ -462,8 +468,7 @@
return -1;
}
- realdatastart = target_mmap(0, data_len + extra +
- MAX_SHARED_LIBS * sizeof(target_ulong),
+ realdatastart = target_mmap(0, data_len + extra + indx_len,
PROT_READ|PROT_WRITE|PROT_EXEC,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
@@ -471,7 +476,7 @@
fprintf(stderr, "Unable to allocate RAM for process data\n");
return realdatastart;
}
- datapos = realdatastart + MAX_SHARED_LIBS * sizeof(target_ulong);
+ datapos = realdatastart + indx_len;
DBG_FLT("BINFMT_FLAT: Allocated data+bss+stack (%d bytes): %x\n",
(int)(data_len + bss_len + stack_len), (int)datapos);
@@ -498,8 +503,7 @@
} else {
- textpos = target_mmap(0, text_len + data_len + extra +
- MAX_SHARED_LIBS * sizeof(target_ulong),
+ textpos = target_mmap(0, text_len + data_len + extra + indx_len,
PROT_READ | PROT_EXEC | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
if (textpos == -1 ) {
@@ -508,9 +512,8 @@
}
realdatastart = textpos + ntohl(hdr->data_start);
- datapos = realdatastart + MAX_SHARED_LIBS * sizeof(target_ulong);
- reloc = (textpos + ntohl(hdr->reloc_start) +
- MAX_SHARED_LIBS * sizeof(target_ulong));
+ datapos = realdatastart + indx_len;
+ reloc = (textpos + ntohl(hdr->reloc_start) + indx_len);
memp = textpos;
#ifdef CONFIG_BINFMT_ZFLAT
@@ -756,6 +759,13 @@
p = copy_strings(p, bprm->argc, bprm->argv);
/* Align stack. */
sp = p & ~(target_ulong)(sizeof(target_ulong) - 1);
+ /* Enforce final stack alignment of 16 bytes. This is sufficient
+ for all current targets, and excess alignment is harmless. */
+ stack_len = bprm->envc + bprm->argc + 2;
+ stack_len += 3; /* argc, arvg, argp */
+ stack_len *= sizeof(target_ulong);
+ if ((sp + stack_len) & 15)
+ sp -= 16 - ((sp + stack_len) & 15);
sp = loader_build_argptr(bprm->envc, bprm->argc, sp, p, 1);
/* Fake some return addresses to ensure the call chain will
Added: trunk/src/host/qemu-neo1973/linux-user/i386/syscall.h
===================================================================
--- trunk/src/host/qemu-neo1973/linux-user/i386/syscall.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/linux-user/i386/syscall.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,221 @@
+/* default linux values for the selectors */
+#define __USER_CS (0x23)
+#define __USER_DS (0x2B)
+
+struct target_pt_regs {
+ long ebx;
+ long ecx;
+ long edx;
+ long esi;
+ long edi;
+ long ebp;
+ long eax;
+ int xds;
+ int xes;
+ long orig_eax;
+ long eip;
+ int xcs;
+ long eflags;
+ long esp;
+ int xss;
+};
+
+/* ioctls */
+
+#define TARGET_LDT_ENTRIES 8192
+#define TARGET_LDT_ENTRY_SIZE 8
+
+#define TARGET_GDT_ENTRY_TLS_ENTRIES 3
+#define TARGET_GDT_ENTRY_TLS_MIN 6
+#define TARGET_GDT_ENTRY_TLS_MAX (TARGET_GDT_ENTRY_TLS_MIN + TARGET_GDT_ENTRY_TLS_ENTRIES - 1)
+
+struct target_modify_ldt_ldt_s {
+ unsigned int entry_number;
+ target_ulong base_addr;
+ unsigned int limit;
+ unsigned int flags;
+};
+
+/* vm86 defines */
+
+#define TARGET_BIOSSEG 0x0f000
+
+#define TARGET_CPU_086 0
+#define TARGET_CPU_186 1
+#define TARGET_CPU_286 2
+#define TARGET_CPU_386 3
+#define TARGET_CPU_486 4
+#define TARGET_CPU_586 5
+
+#define TARGET_VM86_SIGNAL 0 /* return due to signal */
+#define TARGET_VM86_UNKNOWN 1 /* unhandled GP fault - IO-instruction or similar */
+#define TARGET_VM86_INTx 2 /* int3/int x instruction (ARG = x) */
+#define TARGET_VM86_STI 3 /* sti/popf/iret instruction enabled virtual interrupts */
+
+/*
+ * Additional return values when invoking new vm86()
+ */
+#define TARGET_VM86_PICRETURN 4 /* return due to pending PIC request */
+#define TARGET_VM86_TRAP 6 /* return due to DOS-debugger request */
+
+/*
+ * function codes when invoking new vm86()
+ */
+#define TARGET_VM86_PLUS_INSTALL_CHECK 0
+#define TARGET_VM86_ENTER 1
+#define TARGET_VM86_ENTER_NO_BYPASS 2
+#define TARGET_VM86_REQUEST_IRQ 3
+#define TARGET_VM86_FREE_IRQ 4
+#define TARGET_VM86_GET_IRQ_BITS 5
+#define TARGET_VM86_GET_AND_RESET_IRQ 6
+
+/*
+ * This is the stack-layout seen by the user space program when we have
+ * done a translation of "SAVE_ALL" from vm86 mode. The real kernel layout
+ * is 'kernel_vm86_regs' (see below).
+ */
+
+struct target_vm86_regs {
+/*
+ * normal regs, with special meaning for the segment descriptors..
+ */
+ target_long ebx;
+ target_long ecx;
+ target_long edx;
+ target_long esi;
+ target_long edi;
+ target_long ebp;
+ target_long eax;
+ target_long __null_ds;
+ target_long __null_es;
+ target_long __null_fs;
+ target_long __null_gs;
+ target_long orig_eax;
+ target_long eip;
+ unsigned short cs, __csh;
+ target_long eflags;
+ target_long esp;
+ unsigned short ss, __ssh;
+/*
+ * these are specific to v86 mode:
+ */
+ unsigned short es, __esh;
+ unsigned short ds, __dsh;
+ unsigned short fs, __fsh;
+ unsigned short gs, __gsh;
+};
+
+struct target_revectored_struct {
+ target_ulong __map[8]; /* 256 bits */
+};
+
+struct target_vm86_struct {
+ struct target_vm86_regs regs;
+ target_ulong flags;
+ target_ulong screen_bitmap;
+ target_ulong cpu_type;
+ struct target_revectored_struct int_revectored;
+ struct target_revectored_struct int21_revectored;
+};
+
+/*
+ * flags masks
+ */
+#define TARGET_VM86_SCREEN_BITMAP 0x0001
+
+struct target_vm86plus_info_struct {
+ target_ulong flags;
+#define TARGET_force_return_for_pic (1 << 0)
+#define TARGET_vm86dbg_active (1 << 1) /* for debugger */
+#define TARGET_vm86dbg_TFpendig (1 << 2) /* for debugger */
+#define TARGET_is_vm86pus (1 << 31) /* for vm86 internal use */
+ unsigned char vm86dbg_intxxtab[32]; /* for debugger */
+};
+
+struct target_vm86plus_struct {
+ struct target_vm86_regs regs;
+ target_ulong flags;
+ target_ulong screen_bitmap;
+ target_ulong cpu_type;
+ struct target_revectored_struct int_revectored;
+ struct target_revectored_struct int21_revectored;
+ struct target_vm86plus_info_struct vm86plus;
+};
+
+/* ipcs */
+
+#define TARGET_SEMOP 1
+#define TARGET_SEMGET 2
+#define TARGET_SEMCTL 3
+#define TARGET_MSGSND 11
+#define TARGET_MSGRCV 12
+#define TARGET_MSGGET 13
+#define TARGET_MSGCTL 14
+#define TARGET_SHMAT 21
+#define TARGET_SHMDT 22
+#define TARGET_SHMGET 23
+#define TARGET_SHMCTL 24
+
+struct target_msgbuf {
+ int mtype;
+ char mtext[1];
+};
+
+struct target_ipc_kludge {
+ unsigned int msgp; /* Really (struct msgbuf *) */
+ int msgtyp;
+};
+
+struct target_ipc_perm {
+ int key;
+ unsigned short uid;
+ unsigned short gid;
+ unsigned short cuid;
+ unsigned short cgid;
+ unsigned short mode;
+ unsigned short seq;
+};
+
+struct target_msqid_ds {
+ struct target_ipc_perm msg_perm;
+ unsigned int msg_first; /* really struct target_msg* */
+ unsigned int msg_last; /* really struct target_msg* */
+ unsigned int msg_stime; /* really target_time_t */
+ unsigned int msg_rtime; /* really target_time_t */
+ unsigned int msg_ctime; /* really target_time_t */
+ unsigned int wwait; /* really struct wait_queue* */
+ unsigned int rwait; /* really struct wait_queue* */
+ unsigned short msg_cbytes;
+ unsigned short msg_qnum;
+ unsigned short msg_qbytes;
+ unsigned short msg_lspid;
+ unsigned short msg_lrpid;
+};
+
+struct target_shmid_ds {
+ struct target_ipc_perm shm_perm;
+ int shm_segsz;
+ unsigned int shm_atime; /* really target_time_t */
+ unsigned int shm_dtime; /* really target_time_t */
+ unsigned int shm_ctime; /* really target_time_t */
+ unsigned short shm_cpid;
+ unsigned short shm_lpid;
+ short shm_nattch;
+ unsigned short shm_npages;
+ unsigned long *shm_pages;
+ void *attaches; /* really struct shm_desc * */
+};
+
+#define TARGET_IPC_RMID 0
+#define TARGET_IPC_SET 1
+#define TARGET_IPC_STAT 2
+
+union target_semun {
+ int val;
+ unsigned int buf; /* really struct semid_ds * */
+ unsigned int array; /* really unsigned short * */
+ unsigned int __buf; /* really struct seminfo * */
+ unsigned int __pad; /* really void* */
+};
+
+#define UNAME_MACHINE "i686"
Added: trunk/src/host/qemu-neo1973/linux-user/i386/syscall_nr.h
===================================================================
--- trunk/src/host/qemu-neo1973/linux-user/i386/syscall_nr.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/linux-user/i386/syscall_nr.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,274 @@
+/*
+ * This file contains the system call numbers.
+ */
+
+#define TARGET_NR_restart_syscall 0
+#define TARGET_NR_exit 1
+#define TARGET_NR_fork 2
+#define TARGET_NR_read 3
+#define TARGET_NR_write 4
+#define TARGET_NR_open 5
+#define TARGET_NR_close 6
+#define TARGET_NR_waitpid 7
+#define TARGET_NR_creat 8
+#define TARGET_NR_link 9
+#define TARGET_NR_unlink 10
+#define TARGET_NR_execve 11
+#define TARGET_NR_chdir 12
+#define TARGET_NR_time 13
+#define TARGET_NR_mknod 14
+#define TARGET_NR_chmod 15
+#define TARGET_NR_lchown 16
+#define TARGET_NR_break 17
+#define TARGET_NR_oldstat 18
+#define TARGET_NR_lseek 19
+#define TARGET_NR_getpid 20
+#define TARGET_NR_mount 21
+#define TARGET_NR_umount 22
+#define TARGET_NR_setuid 23
+#define TARGET_NR_getuid 24
+#define TARGET_NR_stime 25
+#define TARGET_NR_ptrace 26
+#define TARGET_NR_alarm 27
+#define TARGET_NR_oldfstat 28
+#define TARGET_NR_pause 29
+#define TARGET_NR_utime 30
+#define TARGET_NR_stty 31
+#define TARGET_NR_gtty 32
+#define TARGET_NR_access 33
+#define TARGET_NR_nice 34
+#define TARGET_NR_ftime 35
+#define TARGET_NR_sync 36
+#define TARGET_NR_kill 37
+#define TARGET_NR_rename 38
+#define TARGET_NR_mkdir 39
+#define TARGET_NR_rmdir 40
+#define TARGET_NR_dup 41
+#define TARGET_NR_pipe 42
+#define TARGET_NR_times 43
+#define TARGET_NR_prof 44
+#define TARGET_NR_brk 45
+#define TARGET_NR_setgid 46
+#define TARGET_NR_getgid 47
+#define TARGET_NR_signal 48
+#define TARGET_NR_geteuid 49
+#define TARGET_NR_getegid 50
+#define TARGET_NR_acct 51
+#define TARGET_NR_umount2 52
+#define TARGET_NR_lock 53
+#define TARGET_NR_ioctl 54
+#define TARGET_NR_fcntl 55
+#define TARGET_NR_mpx 56
+#define TARGET_NR_setpgid 57
+#define TARGET_NR_ulimit 58
+#define TARGET_NR_oldolduname 59
+#define TARGET_NR_umask 60
+#define TARGET_NR_chroot 61
+#define TARGET_NR_ustat 62
+#define TARGET_NR_dup2 63
+#define TARGET_NR_getppid 64
+#define TARGET_NR_getpgrp 65
+#define TARGET_NR_setsid 66
+#define TARGET_NR_sigaction 67
+#define TARGET_NR_sgetmask 68
+#define TARGET_NR_ssetmask 69
+#define TARGET_NR_setreuid 70
+#define TARGET_NR_setregid 71
+#define TARGET_NR_sigsuspend 72
+#define TARGET_NR_sigpending 73
+#define TARGET_NR_sethostname 74
+#define TARGET_NR_setrlimit 75
+#define TARGET_NR_getrlimit 76 /* Back compatible 2Gig limited rlimit */
+#define TARGET_NR_getrusage 77
+#define TARGET_NR_gettimeofday 78
+#define TARGET_NR_settimeofday 79
+#define TARGET_NR_getgroups 80
+#define TARGET_NR_setgroups 81
+#define TARGET_NR_select 82
+#define TARGET_NR_symlink 83
+#define TARGET_NR_oldlstat 84
+#define TARGET_NR_readlink 85
+#define TARGET_NR_uselib 86
+#define TARGET_NR_swapon 87
+#define TARGET_NR_reboot 88
+#define TARGET_NR_readdir 89
+#define TARGET_NR_mmap 90
+#define TARGET_NR_munmap 91
+#define TARGET_NR_truncate 92
+#define TARGET_NR_ftruncate 93
+#define TARGET_NR_fchmod 94
+#define TARGET_NR_fchown 95
+#define TARGET_NR_getpriority 96
+#define TARGET_NR_setpriority 97
+#define TARGET_NR_profil 98
+#define TARGET_NR_statfs 99
+#define TARGET_NR_fstatfs 100
+#define TARGET_NR_ioperm 101
+#define TARGET_NR_socketcall 102
+#define TARGET_NR_syslog 103
+#define TARGET_NR_setitimer 104
+#define TARGET_NR_getitimer 105
+#define TARGET_NR_stat 106
+#define TARGET_NR_lstat 107
+#define TARGET_NR_fstat 108
+#define TARGET_NR_olduname 109
+#define TARGET_NR_iopl 110
+#define TARGET_NR_vhangup 111
+#define TARGET_NR_idle 112
+#define TARGET_NR_vm86old 113
+#define TARGET_NR_wait4 114
+#define TARGET_NR_swapoff 115
+#define TARGET_NR_sysinfo 116
+#define TARGET_NR_ipc 117
+#define TARGET_NR_fsync 118
+#define TARGET_NR_sigreturn 119
+#define TARGET_NR_clone 120
+#define TARGET_NR_setdomainname 121
+#define TARGET_NR_uname 122
+#define TARGET_NR_modify_ldt 123
+#define TARGET_NR_adjtimex 124
+#define TARGET_NR_mprotect 125
+#define TARGET_NR_sigprocmask 126
+#define TARGET_NR_create_module 127
+#define TARGET_NR_init_module 128
+#define TARGET_NR_delete_module 129
+#define TARGET_NR_get_kernel_syms 130
+#define TARGET_NR_quotactl 131
+#define TARGET_NR_getpgid 132
+#define TARGET_NR_fchdir 133
+#define TARGET_NR_bdflush 134
+#define TARGET_NR_sysfs 135
+#define TARGET_NR_personality 136
+#define TARGET_NR_afs_syscall 137 /* Syscall for Andrew File System */
+#define TARGET_NR_setfsuid 138
+#define TARGET_NR_setfsgid 139
+#define TARGET_NR__llseek 140
+#define TARGET_NR_getdents 141
+#define TARGET_NR__newselect 142
+#define TARGET_NR_flock 143
+#define TARGET_NR_msync 144
+#define TARGET_NR_readv 145
+#define TARGET_NR_writev 146
+#define TARGET_NR_getsid 147
+#define TARGET_NR_fdatasync 148
+#define TARGET_NR__sysctl 149
+#define TARGET_NR_mlock 150
+#define TARGET_NR_munlock 151
+#define TARGET_NR_mlockall 152
+#define TARGET_NR_munlockall 153
+#define TARGET_NR_sched_setparam 154
+#define TARGET_NR_sched_getparam 155
+#define TARGET_NR_sched_setscheduler 156
+#define TARGET_NR_sched_getscheduler 157
+#define TARGET_NR_sched_yield 158
+#define TARGET_NR_sched_get_priority_max 159
+#define TARGET_NR_sched_get_priority_min 160
+#define TARGET_NR_sched_rr_get_interval 161
+#define TARGET_NR_nanosleep 162
+#define TARGET_NR_mremap 163
+#define TARGET_NR_setresuid 164
+#define TARGET_NR_getresuid 165
+#define TARGET_NR_vm86 166
+#define TARGET_NR_query_module 167
+#define TARGET_NR_poll 168
+#define TARGET_NR_nfsservctl 169
+#define TARGET_NR_setresgid 170
+#define TARGET_NR_getresgid 171
+#define TARGET_NR_prctl 172
+#define TARGET_NR_rt_sigreturn 173
+#define TARGET_NR_rt_sigaction 174
+#define TARGET_NR_rt_sigprocmask 175
+#define TARGET_NR_rt_sigpending 176
+#define TARGET_NR_rt_sigtimedwait 177
+#define TARGET_NR_rt_sigqueueinfo 178
+#define TARGET_NR_rt_sigsuspend 179
+#define TARGET_NR_pread 180
+#define TARGET_NR_pwrite 181
+#define TARGET_NR_chown 182
+#define TARGET_NR_getcwd 183
+#define TARGET_NR_capget 184
+#define TARGET_NR_capset 185
+#define TARGET_NR_sigaltstack 186
+#define TARGET_NR_sendfile 187
+#define TARGET_NR_getpmsg 188 /* some people actually want streams */
+#define TARGET_NR_putpmsg 189 /* some people actually want streams */
+#define TARGET_NR_vfork 190
+#define TARGET_NR_ugetrlimit 191 /* SuS compliant getrlimit */
+#define TARGET_NR_mmap2 192
+#define TARGET_NR_truncate64 193
+#define TARGET_NR_ftruncate64 194
+#define TARGET_NR_stat64 195
+#define TARGET_NR_lstat64 196
+#define TARGET_NR_fstat64 197
+#define TARGET_NR_lchown32 198
+#define TARGET_NR_getuid32 199
+#define TARGET_NR_getgid32 200
+#define TARGET_NR_geteuid32 201
+#define TARGET_NR_getegid32 202
+#define TARGET_NR_setreuid32 203
+#define TARGET_NR_setregid32 204
+#define TARGET_NR_getgroups32 205
+#define TARGET_NR_setgroups32 206
+#define TARGET_NR_fchown32 207
+#define TARGET_NR_setresuid32 208
+#define TARGET_NR_getresuid32 209
+#define TARGET_NR_setresgid32 210
+#define TARGET_NR_getresgid32 211
+#define TARGET_NR_chown32 212
+#define TARGET_NR_setuid32 213
+#define TARGET_NR_setgid32 214
+#define TARGET_NR_setfsuid32 215
+#define TARGET_NR_setfsgid32 216
+#define TARGET_NR_pivot_root 217
+#define TARGET_NR_mincore 218
+#define TARGET_NR_madvise 219
+#define TARGET_NR_madvise1 219 /* delete when C lib stub is removed */
+#define TARGET_NR_getdents64 220
+#define TARGET_NR_fcntl64 221
+/* 223 is unused */
+#define TARGET_NR_gettid 224
+#define TARGET_NR_readahead 225
+#define TARGET_NR_setxattr 226
+#define TARGET_NR_lsetxattr 227
+#define TARGET_NR_fsetxattr 228
+#define TARGET_NR_getxattr 229
+#define TARGET_NR_lgetxattr 230
+#define TARGET_NR_fgetxattr 231
+#define TARGET_NR_listxattr 232
+#define TARGET_NR_llistxattr 233
+#define TARGET_NR_flistxattr 234
+#define TARGET_NR_removexattr 235
+#define TARGET_NR_lremovexattr 236
+#define TARGET_NR_fremovexattr 237
+#define TARGET_NR_tkill 238
+#define TARGET_NR_sendfile64 239
+#define TARGET_NR_futex 240
+#define TARGET_NR_sched_setaffinity 241
+#define TARGET_NR_sched_getaffinity 242
+#define TARGET_NR_set_thread_area 243
+#define TARGET_NR_get_thread_area 244
+#define TARGET_NR_io_setup 245
+#define TARGET_NR_io_destroy 246
+#define TARGET_NR_io_getevents 247
+#define TARGET_NR_io_submit 248
+#define TARGET_NR_io_cancel 249
+#define TARGET_NR_fadvise64 250
+
+#define TARGET_NR_exit_group 252
+#define TARGET_NR_lookup_dcookie 253
+#define TARGET_NR_epoll_create 254
+#define TARGET_NR_epoll_ctl 255
+#define TARGET_NR_epoll_wait 256
+#define TARGET_NR_remap_file_pages 257
+#define TARGET_NR_set_tid_address 258
+#define TARGET_NR_timer_create 259
+#define TARGET_NR_timer_settime (TARGET_NR_timer_create+1)
+#define TARGET_NR_timer_gettime (TARGET_NR_timer_create+2)
+#define TARGET_NR_timer_getoverrun (TARGET_NR_timer_create+3)
+#define TARGET_NR_timer_delete (TARGET_NR_timer_create+4)
+#define TARGET_NR_clock_settime (TARGET_NR_timer_create+5)
+#define TARGET_NR_clock_gettime (TARGET_NR_timer_create+6)
+#define TARGET_NR_clock_getres (TARGET_NR_timer_create+7)
+#define TARGET_NR_clock_nanosleep (TARGET_NR_timer_create+8)
+
+#define TARGET_NR_utimes 271
Added: trunk/src/host/qemu-neo1973/linux-user/i386/termbits.h
===================================================================
--- trunk/src/host/qemu-neo1973/linux-user/i386/termbits.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/linux-user/i386/termbits.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,214 @@
+/* from asm/termbits.h */
+
+#define TARGET_NCCS 19
+
+struct target_termios {
+ unsigned int c_iflag; /* input mode flags */
+ unsigned int c_oflag; /* output mode flags */
+ unsigned int c_cflag; /* control mode flags */
+ unsigned int c_lflag; /* local mode flags */
+ unsigned char c_line; /* line discipline */
+ unsigned char c_cc[TARGET_NCCS]; /* control characters */
+};
+
+/* c_iflag bits */
+#define TARGET_IGNBRK 0000001
+#define TARGET_BRKINT 0000002
+#define TARGET_IGNPAR 0000004
+#define TARGET_PARMRK 0000010
+#define TARGET_INPCK 0000020
+#define TARGET_ISTRIP 0000040
+#define TARGET_INLCR 0000100
+#define TARGET_IGNCR 0000200
+#define TARGET_ICRNL 0000400
+#define TARGET_IUCLC 0001000
+#define TARGET_IXON 0002000
+#define TARGET_IXANY 0004000
+#define TARGET_IXOFF 0010000
+#define TARGET_IMAXBEL 0020000
+
+/* c_oflag bits */
+#define TARGET_OPOST 0000001
+#define TARGET_OLCUC 0000002
+#define TARGET_ONLCR 0000004
+#define TARGET_OCRNL 0000010
+#define TARGET_ONOCR 0000020
+#define TARGET_ONLRET 0000040
+#define TARGET_OFILL 0000100
+#define TARGET_OFDEL 0000200
+#define TARGET_NLDLY 0000400
+#define TARGET_NL0 0000000
+#define TARGET_NL1 0000400
+#define TARGET_CRDLY 0003000
+#define TARGET_CR0 0000000
+#define TARGET_CR1 0001000
+#define TARGET_CR2 0002000
+#define TARGET_CR3 0003000
+#define TARGET_TABDLY 0014000
+#define TARGET_TAB0 0000000
+#define TARGET_TAB1 0004000
+#define TARGET_TAB2 0010000
+#define TARGET_TAB3 0014000
+#define TARGET_XTABS 0014000
+#define TARGET_BSDLY 0020000
+#define TARGET_BS0 0000000
+#define TARGET_BS1 0020000
+#define TARGET_VTDLY 0040000
+#define TARGET_VT0 0000000
+#define TARGET_VT1 0040000
+#define TARGET_FFDLY 0100000
+#define TARGET_FF0 0000000
+#define TARGET_FF1 0100000
+
+/* c_cflag bit meaning */
+#define TARGET_CBAUD 0010017
+#define TARGET_B0 0000000 /* hang up */
+#define TARGET_B50 0000001
+#define TARGET_B75 0000002
+#define TARGET_B110 0000003
+#define TARGET_B134 0000004
+#define TARGET_B150 0000005
+#define TARGET_B200 0000006
+#define TARGET_B300 0000007
+#define TARGET_B600 0000010
+#define TARGET_B1200 0000011
+#define TARGET_B1800 0000012
+#define TARGET_B2400 0000013
+#define TARGET_B4800 0000014
+#define TARGET_B9600 0000015
+#define TARGET_B19200 0000016
+#define TARGET_B38400 0000017
+#define TARGET_EXTA B19200
+#define TARGET_EXTB B38400
+#define TARGET_CSIZE 0000060
+#define TARGET_CS5 0000000
+#define TARGET_CS6 0000020
+#define TARGET_CS7 0000040
+#define TARGET_CS8 0000060
+#define TARGET_CSTOPB 0000100
+#define TARGET_CREAD 0000200
+#define TARGET_PARENB 0000400
+#define TARGET_PARODD 0001000
+#define TARGET_HUPCL 0002000
+#define TARGET_CLOCAL 0004000
+#define TARGET_CBAUDEX 0010000
+#define TARGET_B57600 0010001
+#define TARGET_B115200 0010002
+#define TARGET_B230400 0010003
+#define TARGET_B460800 0010004
+#define TARGET_CIBAUD 002003600000 /* input baud rate (not used) */
+#define TARGET_CRTSCTS 020000000000 /* flow control */
+
+/* c_lflag bits */
+#define TARGET_ISIG 0000001
+#define TARGET_ICANON 0000002
+#define TARGET_XCASE 0000004
+#define TARGET_ECHO 0000010
+#define TARGET_ECHOE 0000020
+#define TARGET_ECHOK 0000040
+#define TARGET_ECHONL 0000100
+#define TARGET_NOFLSH 0000200
+#define TARGET_TOSTOP 0000400
+#define TARGET_ECHOCTL 0001000
+#define TARGET_ECHOPRT 0002000
+#define TARGET_ECHOKE 0004000
+#define TARGET_FLUSHO 0010000
+#define TARGET_PENDIN 0040000
+#define TARGET_IEXTEN 0100000
+
+/* c_cc character offsets */
+#define TARGET_VINTR 0
+#define TARGET_VQUIT 1
+#define TARGET_VERASE 2
+#define TARGET_VKILL 3
+#define TARGET_VEOF 4
+#define TARGET_VTIME 5
+#define TARGET_VMIN 6
+#define TARGET_VSWTC 7
+#define TARGET_VSTART 8
+#define TARGET_VSTOP 9
+#define TARGET_VSUSP 10
+#define TARGET_VEOL 11
+#define TARGET_VREPRINT 12
+#define TARGET_VDISCARD 13
+#define TARGET_VWERASE 14
+#define TARGET_VLNEXT 15
+#define TARGET_VEOL2 16
+
+/* ioctls */
+
+#define TARGET_TCGETS 0x5401
+#define TARGET_TCSETS 0x5402
+#define TARGET_TCSETSW 0x5403
+#define TARGET_TCSETSF 0x5404
+#define TARGET_TCGETA 0x5405
+#define TARGET_TCSETA 0x5406
+#define TARGET_TCSETAW 0x5407
+#define TARGET_TCSETAF 0x5408
+#define TARGET_TCSBRK 0x5409
+#define TARGET_TCXONC 0x540A
+#define TARGET_TCFLSH 0x540B
+
+#define TARGET_TIOCEXCL 0x540C
+#define TARGET_TIOCNXCL 0x540D
+#define TARGET_TIOCSCTTY 0x540E
+#define TARGET_TIOCGPGRP 0x540F
+#define TARGET_TIOCSPGRP 0x5410
+#define TARGET_TIOCOUTQ 0x5411
+#define TARGET_TIOCSTI 0x5412
+#define TARGET_TIOCGWINSZ 0x5413
+#define TARGET_TIOCSWINSZ 0x5414
+#define TARGET_TIOCMGET 0x5415
+#define TARGET_TIOCMBIS 0x5416
+#define TARGET_TIOCMBIC 0x5417
+#define TARGET_TIOCMSET 0x5418
+#define TARGET_TIOCGSOFTCAR 0x5419
+#define TARGET_TIOCSSOFTCAR 0x541A
+#define TARGET_FIONREAD 0x541B
+#define TARGET_TIOCINQ TARGET_FIONREAD
+#define TARGET_TIOCLINUX 0x541C
+#define TARGET_TIOCCONS 0x541D
+#define TARGET_TIOCGSERIAL 0x541E
+#define TARGET_TIOCSSERIAL 0x541F
+#define TARGET_TIOCPKT 0x5420
+#define TARGET_FIONBIO 0x5421
+#define TARGET_TIOCNOTTY 0x5422
+#define TARGET_TIOCSETD 0x5423
+#define TARGET_TIOCGETD 0x5424
+#define TARGET_TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */
+#define TARGET_TIOCTTYGSTRUCT 0x5426 /* For debugging only */
+#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */
+#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */
+#define TARGET_TIOCGSID 0x5429 /* Return the session ID of FD */
+#define TARGET_TIOCGPTN TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
+#define TARGET_TIOCSPTLCK TARGET_IOW('T',0x31, int) /* Lock/unlock Pty */
+
+#define TARGET_FIONCLEX 0x5450 /* these numbers need to be adjusted. */
+#define TARGET_FIOCLEX 0x5451
+#define TARGET_FIOASYNC 0x5452
+#define TARGET_TIOCSERCONFIG 0x5453
+#define TARGET_TIOCSERGWILD 0x5454
+#define TARGET_TIOCSERSWILD 0x5455
+#define TARGET_TIOCGLCKTRMIOS 0x5456
+#define TARGET_TIOCSLCKTRMIOS 0x5457
+#define TARGET_TIOCSERGSTRUCT 0x5458 /* For debugging only */
+#define TARGET_TIOCSERGETLSR 0x5459 /* Get line status register */
+#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config */
+#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */
+
+#define TARGET_TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */
+#define TARGET_TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */
+#define TARGET_TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */
+#define TARGET_TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */
+
+/* Used for packet mode */
+#define TARGET_TIOCPKT_DATA 0
+#define TARGET_TIOCPKT_FLUSHREAD 1
+#define TARGET_TIOCPKT_FLUSHWRITE 2
+#define TARGET_TIOCPKT_STOP 4
+#define TARGET_TIOCPKT_START 8
+#define TARGET_TIOCPKT_NOSTOP 16
+#define TARGET_TIOCPKT_DOSTOP 32
+
+#define TARGET_TIOCSER_TEMT 0x01 /* Transmitter physically empty */
+
Modified: trunk/src/host/qemu-neo1973/linux-user/main.c
===================================================================
--- trunk/src/host/qemu-neo1973/linux-user/main.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/linux-user/main.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -194,9 +194,12 @@
queue_signal(info.si_signo, &info);
break;
case EXCP0D_GPF:
+#ifndef TARGET_X86_64
if (env->eflags & VM_MASK) {
handle_vm86_fault(env);
- } else {
+ } else
+#endif
+ {
info.si_signo = SIGSEGV;
info.si_errno = 0;
info.si_code = TARGET_SI_KERNEL;
@@ -215,9 +218,12 @@
queue_signal(info.si_signo, &info);
break;
case EXCP00_DIVZ:
+#ifndef TARGET_X86_64
if (env->eflags & VM_MASK) {
handle_vm86_trap(env, trapnr);
- } else {
+ } else
+#endif
+ {
/* division by zero */
info.si_signo = SIGFPE;
info.si_errno = 0;
@@ -228,9 +234,12 @@
break;
case EXCP01_SSTP:
case EXCP03_INT3:
+#ifndef TARGET_X86_64
if (env->eflags & VM_MASK) {
handle_vm86_trap(env, trapnr);
- } else {
+ } else
+#endif
+ {
info.si_signo = SIGTRAP;
info.si_errno = 0;
if (trapnr == EXCP01_SSTP) {
@@ -245,9 +254,12 @@
break;
case EXCP04_INTO:
case EXCP05_BOUND:
+#ifndef TARGET_X86_64
if (env->eflags & VM_MASK) {
handle_vm86_trap(env, trapnr);
- } else {
+ } else
+#endif
+ {
info.si_signo = SIGSEGV;
info.si_errno = 0;
info.si_code = TARGET_SI_KERNEL;
@@ -670,18 +682,23 @@
{
cpu_ppc_store_tb(env, ((uint64_t)cpu_ppc_load_tbl(env) << 32) | value);
}
-
-uint32_t cpu_ppc_load_decr (CPUState *env)
+
+void cpu_ppc601_store_rtcu (CPUState *env, uint32_t value)
+__attribute__ (( alias ("cpu_ppc_store_tbu") ));
+
+uint32_t cpu_ppc601_load_rtcu (CPUState *env)
+__attribute__ (( alias ("cpu_ppc_load_tbu") ));
+
+void cpu_ppc601_store_rtcl (CPUState *env, uint32_t value)
{
- /* TO FIX */
- return -1;
+ cpu_ppc_store_tbl(env, value & 0x3FFFFF80);
}
-
-void cpu_ppc_store_decr (CPUState *env, uint32_t value)
+
+uint32_t cpu_ppc601_load_rtcl (CPUState *env)
{
- /* TO FIX */
+ return cpu_ppc_load_tbl(env) & 0x3FFFFF80;
}
-
+
void cpu_loop(CPUPPCState *env)
{
target_siginfo_t info;
@@ -738,10 +755,10 @@
info._sifields._sigfault._addr = env->nip - 4;
queue_signal(info.si_signo, &info);
case EXCP_DSI:
- fprintf(stderr, "Invalid data memory access: 0x%08x\n",
+ fprintf(stderr, "Invalid data memory access: 0x" ADDRX "\n",
env->spr[SPR_DAR]);
if (loglevel) {
- fprintf(logfile, "Invalid data memory access: 0x%08x\n",
+ fprintf(logfile, "Invalid data memory access: 0x" ADDRX "\n",
env->spr[SPR_DAR]);
}
switch (env->error_code & 0xFF000000) {
@@ -1297,6 +1314,7 @@
MIPS_SYS(sys_add_key , 5)
MIPS_SYS(sys_request_key , 4)
MIPS_SYS(sys_keyctl , 5)
+ MIPS_SYS(sys_set_thread_area, 1)
};
#undef MIPS_SYS
@@ -1528,16 +1546,107 @@
}
#endif /* TARGET_M68K */
+#ifdef TARGET_ALPHA
+void cpu_loop (CPUState *env)
+{
+ int trapnr;
+ target_siginfo_t info;
+
+ while (1) {
+ trapnr = cpu_alpha_exec (env);
+
+ switch (trapnr) {
+ case EXCP_RESET:
+ fprintf(stderr, "Reset requested. Exit\n");
+ exit(1);
+ break;
+ case EXCP_MCHK:
+ fprintf(stderr, "Machine check exception. Exit\n");
+ exit(1);
+ break;
+ case EXCP_ARITH:
+ fprintf(stderr, "Arithmetic trap.\n");
+ exit(1);
+ break;
+ case EXCP_HW_INTERRUPT:
+ fprintf(stderr, "External interrupt. Exit\n");
+ exit(1);
+ break;
+ case EXCP_DFAULT:
+ fprintf(stderr, "MMU data fault\n");
+ exit(1);
+ break;
+ case EXCP_DTB_MISS_PAL:
+ fprintf(stderr, "MMU data TLB miss in PALcode\n");
+ exit(1);
+ break;
+ case EXCP_ITB_MISS:
+ fprintf(stderr, "MMU instruction TLB miss\n");
+ exit(1);
+ break;
+ case EXCP_ITB_ACV:
+ fprintf(stderr, "MMU instruction access violation\n");
+ exit(1);
+ break;
+ case EXCP_DTB_MISS_NATIVE:
+ fprintf(stderr, "MMU data TLB miss\n");
+ exit(1);
+ break;
+ case EXCP_UNALIGN:
+ fprintf(stderr, "Unaligned access\n");
+ exit(1);
+ break;
+ case EXCP_OPCDEC:
+ fprintf(stderr, "Invalid instruction\n");
+ exit(1);
+ break;
+ case EXCP_FEN:
+ fprintf(stderr, "Floating-point not allowed\n");
+ exit(1);
+ break;
+ case EXCP_CALL_PAL ... (EXCP_CALL_PALP - 1):
+ fprintf(stderr, "Call to PALcode\n");
+ call_pal(env, (trapnr >> 6) | 0x80);
+ break;
+ case EXCP_CALL_PALP ... (EXCP_CALL_PALE - 1):
+ fprintf(stderr, "Priviledged call to PALcode\n");
+ exit(1);
+ break;
+ case EXCP_DEBUG:
+ {
+ int sig;
+
+ sig = gdb_handlesig (env, TARGET_SIGTRAP);
+ if (sig)
+ {
+ info.si_signo = sig;
+ info.si_errno = 0;
+ info.si_code = TARGET_TRAP_BRKPT;
+ queue_signal(info.si_signo, &info);
+ }
+ }
+ break;
+ default:
+ printf ("Unhandled trap: 0x%x\n", trapnr);
+ cpu_dump_state(env, stderr, fprintf, 0);
+ exit (1);
+ }
+ process_pending_signals (env);
+ }
+}
+#endif /* TARGET_ALPHA */
+
void usage(void)
{
- printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003-2005 Fabrice Bellard\n"
- "usage: qemu-" TARGET_ARCH " [-h] [-g] [-d opts] [-L path] [-s size] program [arguments...]\n"
+ printf("qemu-" TARGET_ARCH " version " QEMU_VERSION ", Copyright (c) 2003-2007 Fabrice Bellard\n"
+ "usage: qemu-" TARGET_ARCH " [-h] [-g] [-d opts] [-L path] [-s size] [-cpu model] program [arguments...]\n"
"Linux CPU emulator (compiled for %s emulation)\n"
"\n"
"-h print this help\n"
"-g port wait gdb connection to port\n"
"-L path set the elf interpreter prefix (default=%s)\n"
"-s size set the stack size in bytes (default=%ld)\n"
+ "-cpu model select CPU (-cpu ? for list)\n"
"\n"
"debug options:\n"
#ifdef USE_CODE_COPY
@@ -1561,6 +1670,7 @@
int main(int argc, char **argv)
{
const char *filename;
+ const char *cpu_model;
struct target_pt_regs regs1, *regs = ®s1;
struct image_info info1, *info = &info1;
TaskState ts1, *ts = &ts1;
@@ -1575,6 +1685,7 @@
/* init debug */
cpu_set_log_filename(DEBUG_LOGFILE);
+ cpu_model = NULL;
optind = 1;
for(;;) {
if (optind >= argc)
@@ -1625,6 +1736,20 @@
gdbstub_port = atoi(argv[optind++]);
} else if (!strcmp(r, "r")) {
qemu_uname_release = argv[optind++];
+ } else if (!strcmp(r, "cpu")) {
+ cpu_model = argv[optind++];
+ if (strcmp(cpu_model, "?") == 0) {
+#if defined(TARGET_PPC)
+ ppc_cpu_list(stdout, &fprintf);
+#elif defined(TARGET_ARM)
+ arm_cpu_list();
+#elif defined(TARGET_MIPS)
+ mips_cpu_list(stdout, &fprintf);
+#elif defined(TARGET_SPARC)
+ sparc_cpu_list(stdout, &fprintf);
+#endif
+ _exit(1);
+ }
} else
#ifdef USE_CODE_COPY
if (!strcmp(r, "no-code-copy")) {
@@ -1696,6 +1821,17 @@
env->eflags |= IF_MASK;
/* linux register setup */
+#if defined(TARGET_X86_64)
+ env->regs[R_EAX] = regs->rax;
+ env->regs[R_EBX] = regs->rbx;
+ env->regs[R_ECX] = regs->rcx;
+ env->regs[R_EDX] = regs->rdx;
+ env->regs[R_ESI] = regs->rsi;
+ env->regs[R_EDI] = regs->rdi;
+ env->regs[R_EBP] = regs->rbp;
+ env->regs[R_ESP] = regs->rsp;
+ env->eip = regs->rip;
+#else
env->regs[R_EAX] = regs->eax;
env->regs[R_EBX] = regs->ebx;
env->regs[R_ECX] = regs->ecx;
@@ -1705,6 +1841,7 @@
env->regs[R_EBP] = regs->ebp;
env->regs[R_ESP] = regs->esp;
env->eip = regs->eip;
+#endif
/* linux interrupt setup */
env->idt.base = h2g(idt_table);
@@ -1750,7 +1887,9 @@
#elif defined(TARGET_ARM)
{
int i;
- cpu_arm_set_model(env, ARM_CPUID_ARM1026);
+ if (cpu_model == NULL)
+ cpu_model = "arm926";
+ cpu_arm_set_model(env, cpu_model);
cpsr_write(env, regs->uregs[16], 0xffffffff);
for(i = 0; i < 16; i++) {
env->regs[i] = regs->uregs[i];
@@ -1763,6 +1902,20 @@
#elif defined(TARGET_SPARC)
{
int i;
+ const sparc_def_t *def;
+#ifdef TARGET_SPARC64
+ if (cpu_model == NULL)
+ cpu_model = "TI UltraSparc II";
+#else
+ if (cpu_model == NULL)
+ cpu_model = "Fujitsu MB86904";
+#endif
+ sparc_find_by_name(cpu_model, &def);
+ if (def == NULL) {
+ fprintf(stderr, "Unable to find Sparc CPU definition\n");
+ exit(1);
+ }
+ cpu_sparc_register(env, def);
env->pc = regs->pc;
env->npc = regs->npc;
env->y = regs->y;
@@ -1777,15 +1930,9 @@
int i;
/* Choose and initialise CPU */
- /* XXX: CPU model (or PVR) should be provided on command line */
- // ppc_find_by_name("750gx", &def);
- // ppc_find_by_name("750fx", &def);
- // ppc_find_by_name("750p", &def);
- ppc_find_by_name("750", &def);
- // ppc_find_by_name("G3", &def);
- // ppc_find_by_name("604r", &def);
- // ppc_find_by_name("604e", &def);
- // ppc_find_by_name("604", &def);
+ if (cpu_model == NULL)
+ cpu_model = "750";
+ ppc_find_by_name(cpu_model, &def);
if (def == NULL) {
cpu_abort(env,
"Unable to find PowerPC CPU definition\n");
@@ -1796,6 +1943,9 @@
if (i != 12 && i != 6 && i != 13)
env->msr[i] = (regs->msr >> i) & 1;
}
+#if defined(TARGET_PPC64)
+ msr_sf = 1;
+#endif
env->nip = regs->nip;
for(i = 0; i < 32; i++) {
env->gpr[i] = regs->gpr[i];
@@ -1832,15 +1982,24 @@
}
#elif defined(TARGET_MIPS)
{
+ mips_def_t *def;
int i;
+ /* Choose and initialise CPU */
+ if (cpu_model == NULL)
+ cpu_model = "24Kf";
+ mips_find_by_name(cpu_model, &def);
+ if (def == NULL)
+ cpu_abort(env, "Unable to find MIPS CPU definition\n");
+ cpu_mips_register(env, def);
+
for(i = 0; i < 32; i++) {
env->gpr[i] = regs->regs[i];
}
env->PC = regs->cp0_epc;
-#ifdef MIPS_USES_FPU
- env->CP0_Status |= (1 << CP0St_CU1);
-#endif
+ if (env->CP0_Config1 & (1 << CP0C1_FP)) {
+ env->CP0_Status |= (1 << CP0St_CU1);
+ }
}
#elif defined(TARGET_SH4)
{
@@ -1851,6 +2010,18 @@
}
env->pc = regs->pc;
}
+#elif defined(TARGET_ALPHA)
+ {
+ int i;
+
+ for(i = 0; i < 28; i++) {
+ env->ir[i] = ((target_ulong *)regs)[i];
+ }
+ env->ipr[IPR_USP] = regs->usp;
+ env->ir[30] = regs->usp;
+ env->pc = regs->pc;
+ env->unique = regs->unique;
+ }
#else
#error unsupported target CPU
#endif
Modified: trunk/src/host/qemu-neo1973/linux-user/mips/syscall_nr.h
===================================================================
--- trunk/src/host/qemu-neo1973/linux-user/mips/syscall_nr.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/linux-user/mips/syscall_nr.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -285,4 +285,4 @@
#define TARGET_NR_add_key (TARGET_NR_Linux + 280)
#define TARGET_NR_request_key (TARGET_NR_Linux + 281)
#define TARGET_NR_keyctl (TARGET_NR_Linux + 282)
-
+#define TARGET_NR_set_thread_area (TARGET_NR_Linux + 283)
Modified: trunk/src/host/qemu-neo1973/linux-user/ppc/termbits.h
===================================================================
--- trunk/src/host/qemu-neo1973/linux-user/ppc/termbits.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/linux-user/ppc/termbits.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -7,8 +7,8 @@
unsigned int c_oflag; /* output mode flags */
unsigned int c_cflag; /* control mode flags */
unsigned int c_lflag; /* local mode flags */
+ unsigned char c_cc[TARGET_NCCS]; /* control characters */
unsigned char c_line; /* line discipline */
- unsigned char c_cc[TARGET_NCCS]; /* control characters */
unsigned int c_ispeed; /* input speed */
unsigned int c_ospeed; /* output speed */
};
Added: trunk/src/host/qemu-neo1973/linux-user/ppc64/syscall.h
===================================================================
--- trunk/src/host/qemu-neo1973/linux-user/ppc64/syscall.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/linux-user/ppc64/syscall.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,130 @@
+/*
+ * PPC emulation for qemu: syscall definitions.
+ *
+ * Copyright (c) 2003 Jocelyn Mayer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* XXX: ABSOLUTELY BUGGY:
+ * for now, this is quite just a cut-and-paste from i386 target...
+ */
+
+/* default linux values for the selectors */
+#define __USER_DS (1)
+
+struct target_pt_regs {
+ unsigned long gpr[32];
+ unsigned long nip;
+ unsigned long msr;
+ unsigned long orig_gpr3; /* Used for restarting system calls */
+ unsigned long ctr;
+ unsigned long link;
+ unsigned long xer;
+ unsigned long ccr;
+ unsigned long mq; /* 601 only (not used at present) */
+ /* Used on APUS to hold IPL value. */
+ unsigned long trap; /* Reason for being here */
+ unsigned long dar; /* Fault registers */
+ unsigned long dsisr;
+ unsigned long result; /* Result of a system call */
+};
+
+/* ioctls */
+struct target_revectored_struct {
+ target_ulong __map[8]; /* 256 bits */
+};
+
+/*
+ * flags masks
+ */
+
+/* ipcs */
+
+#define TARGET_SEMOP 1
+#define TARGET_SEMGET 2
+#define TARGET_SEMCTL 3
+#define TARGET_MSGSND 11
+#define TARGET_MSGRCV 12
+#define TARGET_MSGGET 13
+#define TARGET_MSGCTL 14
+#define TARGET_SHMAT 21
+#define TARGET_SHMDT 22
+#define TARGET_SHMGET 23
+#define TARGET_SHMCTL 24
+
+struct target_msgbuf {
+ int mtype;
+ char mtext[1];
+};
+
+struct target_ipc_kludge {
+ unsigned int msgp; /* Really (struct msgbuf *) */
+ int msgtyp;
+};
+
+struct target_ipc_perm {
+ int key;
+ unsigned short uid;
+ unsigned short gid;
+ unsigned short cuid;
+ unsigned short cgid;
+ unsigned short mode;
+ unsigned short seq;
+};
+
+struct target_msqid_ds {
+ struct target_ipc_perm msg_perm;
+ unsigned int msg_first; /* really struct target_msg* */
+ unsigned int msg_last; /* really struct target_msg* */
+ unsigned int msg_stime; /* really target_time_t */
+ unsigned int msg_rtime; /* really target_time_t */
+ unsigned int msg_ctime; /* really target_time_t */
+ unsigned int wwait; /* really struct wait_queue* */
+ unsigned int rwait; /* really struct wait_queue* */
+ unsigned short msg_cbytes;
+ unsigned short msg_qnum;
+ unsigned short msg_qbytes;
+ unsigned short msg_lspid;
+ unsigned short msg_lrpid;
+};
+
+struct target_shmid_ds {
+ struct target_ipc_perm shm_perm;
+ int shm_segsz;
+ unsigned int shm_atime; /* really target_time_t */
+ unsigned int shm_dtime; /* really target_time_t */
+ unsigned int shm_ctime; /* really target_time_t */
+ unsigned short shm_cpid;
+ unsigned short shm_lpid;
+ short shm_nattch;
+ unsigned short shm_npages;
+ unsigned long *shm_pages;
+ void *attaches; /* really struct shm_desc * */
+};
+
+#define TARGET_IPC_RMID 0
+#define TARGET_IPC_SET 1
+#define TARGET_IPC_STAT 2
+
+union target_semun {
+ int val;
+ unsigned int buf; /* really struct semid_ds * */
+ unsigned int array; /* really unsigned short * */
+ unsigned int __buf; /* really struct seminfo * */
+ unsigned int __pad; /* really void* */
+};
+
+#define UNAME_MACHINE "ppc"
Added: trunk/src/host/qemu-neo1973/linux-user/ppc64/syscall_nr.h
===================================================================
--- trunk/src/host/qemu-neo1973/linux-user/ppc64/syscall_nr.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/linux-user/ppc64/syscall_nr.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,258 @@
+/*
+ * This file contains the system call numbers.
+ */
+#define TARGET_NR_restart_syscall 0
+#define TARGET_NR_exit 1
+#define TARGET_NR_fork 2
+#define TARGET_NR_read 3
+#define TARGET_NR_write 4
+#define TARGET_NR_open 5
+#define TARGET_NR_close 6
+#define TARGET_NR_waitpid 7
+#define TARGET_NR_creat 8
+#define TARGET_NR_link 9
+#define TARGET_NR_unlink 10
+#define TARGET_NR_execve 11
+#define TARGET_NR_chdir 12
+#define TARGET_NR_time 13
+#define TARGET_NR_mknod 14
+#define TARGET_NR_chmod 15
+#define TARGET_NR_lchown32 16
+#define TARGET_NR_break 17
+#define TARGET_NR_oldstat 18
+#define TARGET_NR_lseek 19
+#define TARGET_NR_getpid 20
+#define TARGET_NR_mount 21
+#define TARGET_NR_umount 22
+#define TARGET_NR_setuid32 23
+#define TARGET_NR_getuid32 24
+#define TARGET_NR_stime 25
+#define TARGET_NR_ptrace 26
+#define TARGET_NR_alarm 27
+#define TARGET_NR_oldfstat 28
+#define TARGET_NR_pause 29
+#define TARGET_NR_utime 30
+#define TARGET_NR_stty 31
+#define TARGET_NR_gtty 32
+#define TARGET_NR_access 33
+#define TARGET_NR_nice 34
+#define TARGET_NR_ftime 35
+#define TARGET_NR_sync 36
+#define TARGET_NR_kill 37
+#define TARGET_NR_rename 38
+#define TARGET_NR_mkdir 39
+#define TARGET_NR_rmdir 40
+#define TARGET_NR_dup 41
+#define TARGET_NR_pipe 42
+#define TARGET_NR_times 43
+#define TARGET_NR_prof 44
+#define TARGET_NR_brk 45
+#define TARGET_NR_setgid32 46
+#define TARGET_NR_getgid32 47
+#define TARGET_NR_signal 48
+#define TARGET_NR_geteuid32 49
+#define TARGET_NR_getegid32 50
+#define TARGET_NR_acct 51
+#define TARGET_NR_umount2 52
+#define TARGET_NR_lock 53
+#define TARGET_NR_ioctl 54
+#define TARGET_NR_fcntl 55
+#define TARGET_NR_mpx 56
+#define TARGET_NR_setpgid 57
+#define TARGET_NR_ulimit 58
+#define TARGET_NR_oldolduname 59
+#define TARGET_NR_umask 60
+#define TARGET_NR_chroot 61
+#define TARGET_NR_ustat 62
+#define TARGET_NR_dup2 63
+#define TARGET_NR_getppid 64
+#define TARGET_NR_getpgrp 65
+#define TARGET_NR_setsid 66
+#define TARGET_NR_sigaction 67
+#define TARGET_NR_sgetmask 68
+#define TARGET_NR_ssetmask 69
+#define TARGET_NR_setreuid32 70
+#define TARGET_NR_setregid32 71
+#define TARGET_NR_sigsuspend 72
+#define TARGET_NR_sigpending 73
+#define TARGET_NR_sethostname 74
+#define TARGET_NR_setrlimit 75
+#define TARGET_NR_getrlimit 76
+#define TARGET_NR_getrusage 77
+#define TARGET_NR_gettimeofday 78
+#define TARGET_NR_settimeofday 79
+#define TARGET_NR_getgroups32 80
+#define TARGET_NR_setgroups32 81
+#define TARGET_NR_select 82
+#define TARGET_NR_symlink 83
+#define TARGET_NR_oldlstat 84
+#define TARGET_NR_readlink 85
+#define TARGET_NR_uselib 86
+#define TARGET_NR_swapon 87
+#define TARGET_NR_reboot 88
+#define TARGET_NR_readdir 89
+#define TARGET_NR_mmap 90
+#define TARGET_NR_munmap 91
+#define TARGET_NR_truncate 92
+#define TARGET_NR_ftruncate 93
+#define TARGET_NR_fchmod 94
+#define TARGET_NR_fchown32 95
+#define TARGET_NR_getpriority 96
+#define TARGET_NR_setpriority 97
+#define TARGET_NR_profil 98
+#define TARGET_NR_statfs 99
+#define TARGET_NR_fstatfs 100
+#define TARGET_NR_ioperm 101
+#define TARGET_NR_socketcall 102
+#define TARGET_NR_syslog 103
+#define TARGET_NR_setitimer 104
+#define TARGET_NR_getitimer 105
+#define TARGET_NR_stat 106
+#define TARGET_NR_lstat 107
+#define TARGET_NR_fstat 108
+#define TARGET_NR_olduname 109
+#define TARGET_NR_iopl 110
+#define TARGET_NR_vhangup 111
+#define TARGET_NR_idle 112
+#define TARGET_NR_vm86 113
+#define TARGET_NR_wait4 114
+#define TARGET_NR_swapoff 115
+#define TARGET_NR_sysinfo 116
+#define TARGET_NR_ipc 117
+#define TARGET_NR_fsync 118
+#define TARGET_NR_sigreturn 119
+#define TARGET_NR_clone 120
+#define TARGET_NR_setdomainname 121
+#define TARGET_NR_uname 122
+#define TARGET_NR_modify_ldt 123
+#define TARGET_NR_adjtimex 124
+#define TARGET_NR_mprotect 125
+#define TARGET_NR_sigprocmask 126
+#define TARGET_NR_create_module 127
+#define TARGET_NR_init_module 128
+#define TARGET_NR_delete_module 129
+#define TARGET_NR_get_kernel_syms 130
+#define TARGET_NR_quotactl 131
+#define TARGET_NR_getpgid 132
+#define TARGET_NR_fchdir 133
+#define TARGET_NR_bdflush 134
+#define TARGET_NR_sysfs 135
+#define TARGET_NR_personality 136
+#define TARGET_NR_afs_syscall 137 /* Syscall for Andrew File System */
+#define TARGET_NR_setfsuid32 138
+#define TARGET_NR_setfsgid32 139
+#define TARGET_NR__llseek 140
+#define TARGET_NR_getdents 141
+#define TARGET_NR__newselect 142
+#define TARGET_NR_flock 143
+#define TARGET_NR_msync 144
+#define TARGET_NR_readv 145
+#define TARGET_NR_writev 146
+#define TARGET_NR_getsid 147
+#define TARGET_NR_fdatasync 148
+#define TARGET_NR__sysctl 149
+#define TARGET_NR_mlock 150
+#define TARGET_NR_munlock 151
+#define TARGET_NR_mlockall 152
+#define TARGET_NR_munlockall 153
+#define TARGET_NR_sched_setparam 154
+#define TARGET_NR_sched_getparam 155
+#define TARGET_NR_sched_setscheduler 156
+#define TARGET_NR_sched_getscheduler 157
+#define TARGET_NR_sched_yield 158
+#define TARGET_NR_sched_get_priority_max 159
+#define TARGET_NR_sched_get_priority_min 160
+#define TARGET_NR_sched_rr_get_interval 161
+#define TARGET_NR_nanosleep 162
+#define TARGET_NR_mremap 163
+#define TARGET_NR_setresuid32 164
+#define TARGET_NR_getresuid32 165
+#define TARGET_NR_query_module 166
+#define TARGET_NR_poll 167
+#define TARGET_NR_nfsservctl 168
+#define TARGET_NR_setresgid32 169
+#define TARGET_NR_getresgid32 170
+#define TARGET_NR_prctl 171
+#define TARGET_NR_rt_sigreturn 172
+#define TARGET_NR_rt_sigaction 173
+#define TARGET_NR_rt_sigprocmask 174
+#define TARGET_NR_rt_sigpending 175
+#define TARGET_NR_rt_sigtimedwait 176
+#define TARGET_NR_rt_sigqueueinfo 177
+#define TARGET_NR_rt_sigsuspend 178
+#define TARGET_NR_pread64 179
+#define TARGET_NR_pwrite64 180
+#define TARGET_NR_chown32 181
+#define TARGET_NR_getcwd 182
+#define TARGET_NR_capget 183
+#define TARGET_NR_capset 184
+#define TARGET_NR_sigaltstack 185
+#define TARGET_NR_sendfile 186
+#define TARGET_NR_getpmsg 187 /* some people actually want streams */
+#define TARGET_NR_putpmsg 188 /* some people actually want streams */
+#define TARGET_NR_vfork 189
+#define TARGET_NR_ugetrlimit 190 /* SuS compliant getrlimit */
+#define TARGET_NR_readahead 191
+#define TARGET_NR_mmap2 192
+#define TARGET_NR_truncate64 193
+#define TARGET_NR_ftruncate64 194
+#define TARGET_NR_stat64 195
+#define TARGET_NR_lstat64 196
+#define TARGET_NR_fstat64 197
+#define TARGET_NR_pciconfig_read 198
+#define TARGET_NR_pciconfig_write 199
+#define TARGET_NR_pciconfig_iobase 200
+#define TARGET_NR_multiplexer 201
+#define TARGET_NR_getdents64 202
+#define TARGET_NR_pivot_root 203
+#define TARGET_NR_fcntl64 204
+#define TARGET_NR_madvise 205
+#define TARGET_NR_mincore 206
+#define TARGET_NR_gettid 207
+#define TARGET_NR_tkill 208
+#define TARGET_NR_setxattr 209
+#define TARGET_NR_lsetxattr 210
+#define TARGET_NR_fsetxattr 211
+#define TARGET_NR_getxattr 212
+#define TARGET_NR_lgetxattr 213
+#define TARGET_NR_fgetxattr 214
+#define TARGET_NR_listxattr 215
+#define TARGET_NR_llistxattr 216
+#define TARGET_NR_flistxattr 217
+#define TARGET_NR_removexattr 218
+#define TARGET_NR_lremovexattr 219
+#define TARGET_NR_fremovexattr 220
+#define TARGET_NR_futex 221
+#define TARGET_NR_sched_setaffinity 222
+#define TARGET_NR_sched_getaffinity 223
+/* 224 currently unused */
+#define TARGET_NR_tuxcall 225
+#define TARGET_NR_sendfile64 226
+#define TARGET_NR_io_setup 227
+#define TARGET_NR_io_destroy 228
+#define TARGET_NR_io_getevents 229
+#define TARGET_NR_io_submit 230
+#define TARGET_NR_io_cancel 231
+#define TARGET_NR_set_tid_address 232
+#define TARGET_NR_fadvise64 233
+#define TARGET_NR_exit_group 234
+#define TARGET_NR_lookup_dcookie 235
+#define TARGET_NR_epoll_create 236
+#define TARGET_NR_epoll_ctl 237
+#define TARGET_NR_epoll_wait 238
+#define TARGET_NR_remap_file_pages 239
+#define TARGET_NR_timer_create 240
+#define TARGET_NR_timer_settime 241
+#define TARGET_NR_timer_gettime 242
+#define TARGET_NR_timer_getoverrun 243
+#define TARGET_NR_timer_delete 244
+#define TARGET_NR_clock_settime 245
+#define TARGET_NR_clock_gettime 246
+#define TARGET_NR_clock_getres 247
+#define TARGET_NR_clock_nanosleep 248
+#define TARGET_NR_swapcontext 249
+#define TARGET_NR_tgkill 250
+#define TARGET_NR_utimes 251
+#define TARGET_NR_statfs64 252
+#define TARGET_NR_fstatfs64 253
+#define TARGET_NR_fadvise64_64 254
Added: trunk/src/host/qemu-neo1973/linux-user/ppc64/termbits.h
===================================================================
--- trunk/src/host/qemu-neo1973/linux-user/ppc64/termbits.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/linux-user/ppc64/termbits.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,235 @@
+/* from asm/termbits.h */
+
+#define TARGET_NCCS 19
+
+struct target_termios {
+ unsigned int c_iflag; /* input mode flags */
+ unsigned int c_oflag; /* output mode flags */
+ unsigned int c_cflag; /* control mode flags */
+ unsigned int c_lflag; /* local mode flags */
+ unsigned char c_cc[TARGET_NCCS]; /* control characters */
+ unsigned char c_line; /* line discipline */
+ unsigned int c_ispeed; /* input speed */
+ unsigned int c_ospeed; /* output speed */
+};
+
+/* c_cc character offsets */
+#define TARGET_VINTR 0
+#define TARGET_VQUIT 1
+#define TARGET_VERASE 2
+#define TARGET_VKILL 3
+#define TARGET_VEOF 4
+#define TARGET_VMIN 5
+#define TARGET_VEOL 6
+#define TARGET_VTIME 7
+#define TARGET_VEOL2 8
+#define TARGET_VSWTC 9
+
+#define TARGET_VWERASE 10
+#define TARGET_VREPRINT 11
+#define TARGET_VSUSP 12
+#define TARGET_VSTART 13
+#define TARGET_VSTOP 14
+#define TARGET_VLNEXT 15
+#define TARGET_VDISCARD 16
+
+#define TARGET_IGNBRK 0000001
+#define TARGET_BRKINT 0000002
+#define TARGET_IGNPAR 0000004
+#define TARGET_PARMRK 0000010
+#define TARGET_INPCK 0000020
+#define TARGET_ISTRIP 0000040
+#define TARGET_INLCR 0000100
+#define TARGET_IGNCR 0000200
+#define TARGET_ICRNL 0000400
+#define TARGET_IXON 0001000
+#define TARGET_IXOFF 0002000
+#define TARGET_IXANY 0004000
+#define TARGET_IUCLC 0010000
+#define TARGET_IMAXBEL 0020000
+
+/* c_oflag bits */
+#define TARGET_OPOST 0000001
+#define TARGET_ONLCR 0000002
+#define TARGET_OLCUC 0000004
+
+#define TARGET_OCRNL 0000010
+#define TARGET_ONOCR 0000020
+#define TARGET_ONLRET 0000040
+
+#define TARGET_OFILL 00000100
+#define TARGET_OFDEL 00000200
+#define TARGET_NLDLY 00001400
+#define TARGET_NL0 00000000
+#define TARGET_NL1 00000400
+#define TARGET_NL2 00001000
+#define TARGET_NL3 00001400
+#define TARGET_TABDLY 00006000
+#define TARGET_TAB0 00000000
+#define TARGET_TAB1 00002000
+#define TARGET_TAB2 00004000
+#define TARGET_TAB3 00006000
+#define TARGET_CRDLY 00030000
+#define TARGET_CR0 00000000
+#define TARGET_CR1 00010000
+#define TARGET_CR2 00020000
+#define TARGET_CR3 00030000
+#define TARGET_FFDLY 00040000
+#define TARGET_FF0 00000000
+#define TARGET_FF1 00040000
+#define TARGET_BSDLY 00100000
+#define TARGET_BS0 00000000
+#define TARGET_BS1 00100000
+#define TARGET_VTDLY 00200000
+#define TARGET_VT0 00000000
+#define TARGET_VT1 00200000
+#define TARGET_XTABS 01000000 /* Hmm.. Linux/i386 considers this part of TABDLY.. */
+
+/* c_cflag bit meaning */
+#define TARGET_CBAUD 0000377
+#define TARGET_B0 0000000 /* hang up */
+#define TARGET_B50 0000001
+#define TARGET_B75 0000002
+#define TARGET_B110 0000003
+#define TARGET_B134 0000004
+#define TARGET_B150 0000005
+#define TARGET_B200 0000006
+#define TARGET_B300 0000007
+#define TARGET_B600 0000010
+#define TARGET_B1200 0000011
+#define TARGET_B1800 0000012
+#define TARGET_B2400 0000013
+#define TARGET_B4800 0000014
+#define TARGET_B9600 0000015
+#define TARGET_B19200 0000016
+#define TARGET_B38400 0000017
+#define TARGET_EXTA B19200
+#define TARGET_EXTB B38400
+#define TARGET_CBAUDEX 0000000
+#define TARGET_B57600 00020
+#define TARGET_B115200 00021
+#define TARGET_B230400 00022
+#define TARGET_B460800 00023
+#define TARGET_B500000 00024
+#define TARGET_B576000 00025
+#define TARGET_B921600 00026
+#define TARGET_B1000000 00027
+#define TARGET_B1152000 00030
+#define TARGET_B1500000 00031
+#define TARGET_B2000000 00032
+#define TARGET_B2500000 00033
+#define TARGET_B3000000 00034
+#define TARGET_B3500000 00035
+#define TARGET_B4000000 00036
+
+#define TARGET_CSIZE 00001400
+#define TARGET_CS5 00000000
+#define TARGET_CS6 00000400
+#define TARGET_CS7 00001000
+#define TARGET_CS8 00001400
+
+#define TARGET_CSTOPB 00002000
+#define TARGET_CREAD 00004000
+#define TARGET_PARENB 00010000
+#define TARGET_PARODD 00020000
+#define TARGET_HUPCL 00040000
+
+#define TARGET_CLOCAL 00100000
+#define TARGET_CRTSCTS 020000000000 /* flow control */
+
+/* c_lflag bits */
+#define TARGET_ISIG 0x00000080
+#define TARGET_ICANON 0x00000100
+#define TARGET_XCASE 0x00004000
+#define TARGET_ECHO 0x00000008
+#define TARGET_ECHOE 0x00000002
+#define TARGET_ECHOK 0x00000004
+#define TARGET_ECHONL 0x00000010
+#define TARGET_NOFLSH 0x80000000
+#define TARGET_TOSTOP 0x00400000
+#define TARGET_ECHOCTL 0x00000040
+#define TARGET_ECHOPRT 0x00000020
+#define TARGET_ECHOKE 0x00000001
+#define TARGET_FLUSHO 0x00800000
+#define TARGET_PENDIN 0x20000000
+#define TARGET_IEXTEN 0x00000400
+
+/* ioctls */
+
+#define TARGET_FIOCLEX TARGET_IO('f', 1)
+#define TARGET_FIONCLEX TARGET_IO('f', 2)
+#define TARGET_FIOASYNC TARGET_IOW('f', 125, int)
+#define TARGET_FIONBIO TARGET_IOW('f', 126, int)
+#define TARGET_FIONREAD TARGET_IOR('f', 127, int)
+#define TARGET_TIOCINQ TARGET_FIONREAD
+//#define TARGET_FIOQSIZE TARGET_IOR('f', 128, loff_t)
+
+#define TARGET_TCGETS TARGET_IOR('t', 19, struct target_termios)
+#define TARGET_TCSETS TARGET_IOW('t', 20, struct target_termios)
+#define TARGET_TCSETSW TARGET_IOW('t', 21, struct target_termios)
+#define TARGET_TCSETSF TARGET_IOW('t', 22, struct target_termios)
+
+#define TARGET_TCGETA TARGET_IOR('t', 23, struct target_termio)
+#define TARGET_TCSETA TARGET_IOW('t', 24, struct target_termio)
+#define TARGET_TCSETAW TARGET_IOW('t', 25, struct target_termio)
+#define TARGET_TCSETAF TARGET_IOW('t', 28, struct target_termio)
+
+#define TARGET_TCSBRK TARGET_IO('t', 29)
+#define TARGET_TCXONC TARGET_IO('t', 30)
+#define TARGET_TCFLSH TARGET_IO('t', 31)
+
+#define TARGET_TIOCSWINSZ TARGET_IOW('t', 103, struct target_winsize)
+#define TARGET_TIOCGWINSZ TARGET_IOR('t', 104, struct target_winsize)
+#define TARGET_TIOCSTART TARGET_IO('t', 110) /* start output, like ^Q */
+#define TARGET_TIOCSTOP TARGET_IO('t', 111) /* stop output, like ^S */
+#define TARGET_TIOCOUTQ TARGET_IOR('t', 115, int) /* output queue size */
+
+#define TARGET_TIOCGLTC TARGET_IOR('t', 116, struct target_ltchars)
+#define TARGET_TIOCSLTC TARGET_IOW('t', 117, struct target_ltchars)
+#define TARGET_TIOCSPGRP TARGET_IOW('t', 118, int)
+#define TARGET_TIOCGPGRP TARGET_IOR('t', 119, int)
+
+#define TARGET_TIOCEXCL 0x540C
+#define TARGET_TIOCNXCL 0x540D
+#define TARGET_TIOCSCTTY 0x540E
+
+#define TARGET_TIOCSTI 0x5412
+#define TARGET_TIOCMGET 0x5415
+#define TARGET_TIOCMBIS 0x5416
+#define TARGET_TIOCMBIC 0x5417
+#define TARGET_TIOCMSET 0x5418
+
+#define TARGET_TIOCGSOFTCAR 0x5419
+#define TARGET_TIOCSSOFTCAR 0x541A
+#define TARGET_TIOCLINUX 0x541C
+#define TARGET_TIOCCONS 0x541D
+#define TARGET_TIOCGSERIAL 0x541E
+#define TARGET_TIOCSSERIAL 0x541F
+#define TARGET_TIOCPKT 0x5420
+
+#define TARGET_TIOCNOTTY 0x5422
+#define TARGET_TIOCSETD 0x5423
+#define TARGET_TIOCGETD 0x5424
+#define TARGET_TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */
+#define TARGET_TIOCTTYGSTRUCT 0x5426 /* For debugging only */
+#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */
+#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */
+#define TARGET_TIOCGSID 0x5429 /* Return the session ID of FD */
+#define TARGET_TIOCGPTN TARGET_IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
+#define TARGET_TIOCSPTLCK TARGET_IOW('T',0x31, int) /* Lock/unlock Pty */
+
+#define TARGET_TIOCSERCONFIG 0x5453
+#define TARGET_TIOCSERGWILD 0x5454
+#define TARGET_TIOCSERSWILD 0x5455
+#define TARGET_TIOCGLCKTRMIOS 0x5456
+#define TARGET_TIOCSLCKTRMIOS 0x5457
+#define TARGET_TIOCSERGSTRUCT 0x5458 /* For debugging only */
+#define TARGET_TIOCSERGETLSR 0x5459 /* Get line status register */
+ /* ioctl (fd, TIOCSERGETLSR, &result) where result may be as below */
+# define TARGET_TIOCSER_TEMT 0x01 /* Transmitter physically empty */
+#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config */
+#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */
+
+#define TARGET_TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */
+#define TARGET_TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */
+
Modified: trunk/src/host/qemu-neo1973/linux-user/qemu.h
===================================================================
--- trunk/src/host/qemu-neo1973/linux-user/qemu.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/linux-user/qemu.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -68,7 +68,7 @@
uint32_t heap_limit;
int swi_errno;
#endif
-#ifdef TARGET_I386
+#if defined(TARGET_I386) && !defined(TARGET_X86_64)
target_ulong target_v86;
struct vm86_saved_state vm86_saved_regs;
struct target_vm86plus_struct vm86plus;
Modified: trunk/src/host/qemu-neo1973/linux-user/signal.c
===================================================================
--- trunk/src/host/qemu-neo1973/linux-user/signal.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/linux-user/signal.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -422,7 +422,7 @@
struct sigaction act1;
int host_sig;
- if (sig < 1 || sig > TARGET_NSIG)
+ if (sig < 1 || sig > TARGET_NSIG || sig == SIGKILL || sig == SIGSTOP)
return -EINVAL;
k = &sigact_table[sig - 1];
#if defined(DEBUG_SIGNAL)
@@ -690,7 +690,11 @@
err |= __put_user(frame->retcode, &frame->pretcode);
/* This is popl %eax ; movl $,%eax ; int $0x80 */
err |= __put_user(0xb858, (short *)(frame->retcode+0));
+#if defined(TARGET_X86_64)
+#warning "Fix this !"
+#else
err |= __put_user(TARGET_NR_sigreturn, (int *)(frame->retcode+2));
+#endif
err |= __put_user(0x80cd, (short *)(frame->retcode+6));
}
@@ -2048,7 +2052,7 @@
host_to_target_sigset_internal(&target_old_set, &old_set);
/* if the CPU is in VM86 mode, we restore the 32 bit values */
-#ifdef TARGET_I386
+#if defined(TARGET_I386) && !defined(TARGET_X86_64)
{
CPUX86State *env = cpu_env;
if (env->eflags & VM_MASK)
Modified: trunk/src/host/qemu-neo1973/linux-user/syscall.c
===================================================================
--- trunk/src/host/qemu-neo1973/linux-user/syscall.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/linux-user/syscall.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -28,10 +28,13 @@
#include <fcntl.h>
#include <time.h>
#include <sys/types.h>
+#include <sys/ipc.h>
+#include <sys/msg.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/mount.h>
+#include <sys/prctl.h>
#include <sys/resource.h>
#include <sys/mman.h>
#include <sys/swap.h>
@@ -42,6 +45,7 @@
#include <sys/poll.h>
#include <sys/times.h>
#include <sys/shm.h>
+#include <sys/sem.h>
#include <sys/statfs.h>
#include <utime.h>
#include <sys/sysinfo.h>
@@ -70,7 +74,7 @@
//#define DEBUG
#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) \
- || defined(TARGET_M68K)
+ || defined(TARGET_M68K) || defined(TARGET_SH4)
/* 16 bit uid wrappers emulation */
#define USE_UID16
#endif
@@ -139,6 +143,7 @@
#define __NR_sys_getdents __NR_getdents
#define __NR_sys_getdents64 __NR_getdents64
#define __NR_sys_rt_sigqueueinfo __NR_rt_sigqueueinfo
+#define __NR_sys_syslog __NR_syslog
#if defined(__alpha__) || defined (__ia64__) || defined(__x86_64__)
#define __NR__llseek __NR_lseek
@@ -158,9 +163,13 @@
_syscall5(int, _llseek, uint, fd, ulong, hi, ulong, lo,
loff_t *, res, uint, wh);
_syscall3(int,sys_rt_sigqueueinfo,int,pid,int,sig,siginfo_t *,uinfo)
+_syscall3(int,sys_syslog,int,type,char*,bufp,int,len)
#ifdef __NR_exit_group
_syscall1(int,exit_group,int,error_code)
#endif
+#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
+_syscall1(int,set_tid_address,int *,tidptr)
+#endif
extern int personality(int);
extern int flock(int, int);
@@ -856,7 +865,7 @@
target_ulong target_addrlen)
{
socklen_t addrlen = tget32(target_addrlen);
- void *addr = alloca(target_addrlen);
+ void *addr = alloca(addrlen);
long ret;
ret = get_errno(getpeername(fd, addr, &addrlen));
@@ -871,7 +880,7 @@
target_ulong target_addrlen)
{
socklen_t addrlen = tget32(target_addrlen);
- void *addr = alloca(target_addrlen);
+ void *addr = alloca(addrlen);
long ret;
ret = get_errno(getsockname(fd, addr, &addrlen));
@@ -1114,6 +1123,12 @@
uint32_t size;
} shm_regions[N_SHM_REGIONS];
+union semun {
+ int val;
+ struct senid_ds *buf;
+ unsigned short *array;
+};
+
/* ??? This only works with linear mappings. */
static long do_ipc(long call, long first, long second, long third,
long ptr, long fifth)
@@ -1128,6 +1143,52 @@
call &= 0xffff;
switch (call) {
+ case IPCOP_semop:
+ ret = get_errno(semop(first,(struct sembuf *) ptr, second));
+ break;
+
+ case IPCOP_semget:
+ ret = get_errno(semget(first, second, third));
+ break;
+
+ case IPCOP_semctl:
+ ret = get_errno(semctl(first, second, third, ((union semun*)ptr)->val));
+
+ break;
+
+ case IPCOP_semtimedop:
+ gemu_log("Unsupported ipc call: %ld (version %d)\n", call, version);
+ ret = -ENOSYS;
+ break;
+
+ case IPCOP_msgget:
+ ret = get_errno(msgget(first, second));
+ break;
+
+ case IPCOP_msgsnd:
+ ret = get_errno(msgsnd(first, (struct msgbuf *) ptr, second, third));
+ break;
+
+ case IPCOP_msgctl:
+ ret = get_errno(msgctl(first, second, (struct msqid_ds *) ptr));
+ break;
+
+ case IPCOP_msgrcv:
+ {
+ struct ipc_kludge
+ {
+ void *__unbounded msgp;
+ long int msgtyp;
+ };
+
+ struct ipc_kludge *foo = (struct ipc_kludge *) ptr;
+ struct msgbuf *msgp = (struct msgbuf *) foo->msgp;
+
+ ret = get_errno(msgrcv(first, msgp, second, 0, third));
+
+ }
+ break;
+
case IPCOP_shmat:
/* SHM_* flags are the same on all linux platforms */
ret = get_errno((long) shmat(first, (void *) ptr, second));
@@ -1664,8 +1725,7 @@
ts->next = first_task_state;
first_task_state = ts;
/* we create a new CPU instance. */
- new_env = cpu_init();
- memcpy(new_env, env, sizeof(CPUState));
+ new_env = cpu_copy(env);
#if defined(TARGET_I386)
if (!newsp)
newsp = env->regs[R_ESP];
@@ -1705,6 +1765,16 @@
newsp = env->gregs[15];
new_env->gregs[15] = newsp;
/* XXXXX */
+#elif defined(TARGET_ALPHA)
+ if (!newsp)
+ newsp = env->ir[30];
+ new_env->ir[30] = newsp;
+ /* ? */
+ {
+ int i;
+ for (i = 7; i < 30; i++)
+ new_env->ir[i] = 0;
+ }
#else
#error unsupported target CPU
#endif
@@ -1733,6 +1803,13 @@
switch(cmd) {
case TARGET_F_GETLK:
+ lock_user_struct(target_fl, arg, 1);
+ fl.l_type = tswap16(target_fl->l_type);
+ fl.l_whence = tswap16(target_fl->l_whence);
+ fl.l_start = tswapl(target_fl->l_start);
+ fl.l_len = tswapl(target_fl->l_len);
+ fl.l_pid = tswapl(target_fl->l_pid);
+ unlock_user_struct(target_fl, arg, 0);
ret = fcntl(fd, cmd, &fl);
if (ret == 0) {
lock_user_struct(target_fl, arg, 0);
@@ -1758,6 +1835,13 @@
break;
case TARGET_F_GETLK64:
+ lock_user_struct(target_fl64, arg, 1);
+ fl64.l_type = tswap16(target_fl64->l_type) >> 1;
+ fl64.l_whence = tswap16(target_fl64->l_whence);
+ fl64.l_start = tswapl(target_fl64->l_start);
+ fl64.l_len = tswapl(target_fl64->l_len);
+ fl64.l_pid = tswap16(target_fl64->l_pid);
+ unlock_user_struct(target_fl64, arg, 0);
ret = fcntl(fd, cmd >> 1, &fl64);
if (ret == 0) {
lock_user_struct(target_fl64, arg, 0);
@@ -1983,6 +2067,7 @@
case TARGET_NR_fork:
ret = get_errno(do_fork(cpu_env, SIGCHLD, 0));
break;
+#ifdef TARGET_NR_waitpid
case TARGET_NR_waitpid:
{
int status;
@@ -1991,11 +2076,14 @@
tput32(arg2, status);
}
break;
+#endif
+#ifdef TARGET_NR_creat /* not on alpha */
case TARGET_NR_creat:
p = lock_user_string(arg1);
ret = get_errno(creat(p, arg2));
unlock_user(p, arg1, 0);
break;
+#endif
case TARGET_NR_link:
{
void * p2;
@@ -2103,17 +2191,34 @@
case TARGET_NR_lseek:
ret = get_errno(lseek(arg1, arg2, arg3));
break;
+#ifdef TARGET_NR_getxpid
+ case TARGET_NR_getxpid:
+#else
case TARGET_NR_getpid:
+#endif
ret = get_errno(getpid());
break;
case TARGET_NR_mount:
- /* need to look at the data field */
- goto unimplemented;
+ {
+ /* need to look at the data field */
+ void *p2, *p3;
+ p = lock_user_string(arg1);
+ p2 = lock_user_string(arg2);
+ p3 = lock_user_string(arg3);
+ ret = get_errno(mount(p, p2, p3, (unsigned long)arg4, (const void *)arg5));
+ unlock_user(p, arg1, 0);
+ unlock_user(p2, arg2, 0);
+ unlock_user(p3, arg3, 0);
+ break;
+ }
+#ifdef TARGET_NR_umount
case TARGET_NR_umount:
p = lock_user_string(arg1);
ret = get_errno(umount(p));
unlock_user(p, arg1, 0);
break;
+#endif
+#ifdef TARGET_NR_stime /* not on alpha */
case TARGET_NR_stime:
{
time_t host_time;
@@ -2121,18 +2226,24 @@
ret = get_errno(stime(&host_time));
}
break;
+#endif
case TARGET_NR_ptrace:
goto unimplemented;
+#ifdef TARGET_NR_alarm /* not on alpha */
case TARGET_NR_alarm:
ret = alarm(arg1);
break;
+#endif
#ifdef TARGET_NR_oldfstat
case TARGET_NR_oldfstat:
goto unimplemented;
#endif
+#ifdef TARGET_NR_pause /* not on alpha */
case TARGET_NR_pause:
ret = get_errno(pause());
break;
+#endif
+#ifdef TARGET_NR_utime
case TARGET_NR_utime:
{
struct utimbuf tbuf, *host_tbuf;
@@ -2151,6 +2262,7 @@
unlock_user(p, arg1, 0);
}
break;
+#endif
case TARGET_NR_utimes:
{
struct timeval *tvp, tv[2];
@@ -2180,9 +2292,11 @@
ret = get_errno(access(p, arg2));
unlock_user(p, arg1, 0);
break;
+#ifdef TARGET_NR_nice /* not on alpha */
case TARGET_NR_nice:
ret = get_errno(nice(arg1));
break;
+#endif
#ifdef TARGET_NR_ftime
case TARGET_NR_ftime:
goto unimplemented;
@@ -2247,19 +2361,22 @@
case TARGET_NR_prof:
goto unimplemented;
#endif
+#ifdef TARGET_NR_signal
case TARGET_NR_signal:
goto unimplemented;
-
+#endif
case TARGET_NR_acct:
p = lock_user_string(arg1);
ret = get_errno(acct(path(p)));
unlock_user(p, arg1, 0);
break;
+#ifdef TARGET_NR_umount2 /* not on alpha */
case TARGET_NR_umount2:
p = lock_user_string(arg1);
ret = get_errno(umount2(p, arg2));
unlock_user(p, arg1, 0);
break;
+#endif
#ifdef TARGET_NR_lock
case TARGET_NR_lock:
goto unimplemented;
@@ -2298,15 +2415,18 @@
case TARGET_NR_dup2:
ret = get_errno(dup2(arg1, arg2));
break;
+#ifdef TARGET_NR_getppid /* not on alpha */
case TARGET_NR_getppid:
ret = get_errno(getppid());
break;
+#endif
case TARGET_NR_getpgrp:
ret = get_errno(getpgrp());
break;
case TARGET_NR_setsid:
ret = get_errno(setsid());
break;
+#ifdef TARGET_NR_sigaction
case TARGET_NR_sigaction:
{
#if !defined(TARGET_MIPS)
@@ -2361,6 +2481,7 @@
#endif
}
break;
+#endif
case TARGET_NR_rt_sigaction:
{
struct target_sigaction *act;
@@ -2381,6 +2502,7 @@
unlock_user_struct(oact, arg3, 1);
}
break;
+#ifdef TARGET_NR_sgetmask /* not on alpha */
case TARGET_NR_sgetmask:
{
sigset_t cur_set;
@@ -2390,6 +2512,8 @@
ret = target_set;
}
break;
+#endif
+#ifdef TARGET_NR_ssetmask /* not on alpha */
case TARGET_NR_ssetmask:
{
sigset_t set, oset, cur_set;
@@ -2402,6 +2526,8 @@
ret = target_set;
}
break;
+#endif
+#ifdef TARGET_NR_sigprocmask
case TARGET_NR_sigprocmask:
{
int how = arg1;
@@ -2438,6 +2564,7 @@
}
}
break;
+#endif
case TARGET_NR_rt_sigprocmask:
{
int how = arg1;
@@ -2474,6 +2601,7 @@
}
}
break;
+#ifdef TARGET_NR_sigpending
case TARGET_NR_sigpending:
{
sigset_t set;
@@ -2485,6 +2613,7 @@
}
}
break;
+#endif
case TARGET_NR_rt_sigpending:
{
sigset_t set;
@@ -2496,6 +2625,7 @@
}
}
break;
+#ifdef TARGET_NR_sigsuspend
case TARGET_NR_sigsuspend:
{
sigset_t set;
@@ -2505,6 +2635,7 @@
ret = get_errno(sigsuspend(&set));
}
break;
+#endif
case TARGET_NR_rt_sigsuspend:
{
sigset_t set;
@@ -2546,10 +2677,12 @@
ret = get_errno(sys_rt_sigqueueinfo(arg1, arg2, &uinfo));
}
break;
+#ifdef TARGET_NR_sigreturn
case TARGET_NR_sigreturn:
/* NOTE: ret is eax, so not transcoding must be done */
ret = do_sigreturn(cpu_env);
break;
+#endif
case TARGET_NR_rt_sigreturn:
/* NOTE: ret is eax, so not transcoding must be done */
ret = do_rt_sigreturn(cpu_env);
@@ -2655,17 +2788,24 @@
unlock_user(p, arg1, 0);
}
break;
+#ifdef TARGET_NR_uselib
case TARGET_NR_uselib:
goto unimplemented;
+#endif
+#ifdef TARGET_NR_swapon
case TARGET_NR_swapon:
p = lock_user_string(arg1);
ret = get_errno(swapon(p, arg2));
unlock_user(p, arg1, 0);
break;
+#endif
case TARGET_NR_reboot:
goto unimplemented;
+#ifdef TARGET_NR_readdir
case TARGET_NR_readdir:
goto unimplemented;
+#endif
+#ifdef TARGET_NR_mmap
case TARGET_NR_mmap:
#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_M68K)
{
@@ -2690,6 +2830,7 @@
arg6));
#endif
break;
+#endif
#ifdef TARGET_NR_mmap2
case TARGET_NR_mmap2:
#if defined(TARGET_SPARC) || defined(TARGET_MIPS)
@@ -2709,25 +2850,37 @@
case TARGET_NR_mprotect:
ret = get_errno(target_mprotect(arg1, arg2, arg3));
break;
+#ifdef TARGET_NR_mremap
case TARGET_NR_mremap:
ret = get_errno(target_mremap(arg1, arg2, arg3, arg4, arg5));
break;
+#endif
/* ??? msync/mlock/munlock are broken for softmmu. */
+#ifdef TARGET_NR_msync
case TARGET_NR_msync:
ret = get_errno(msync(g2h(arg1), arg2, arg3));
break;
+#endif
+#ifdef TARGET_NR_mlock
case TARGET_NR_mlock:
ret = get_errno(mlock(g2h(arg1), arg2));
break;
+#endif
+#ifdef TARGET_NR_munlock
case TARGET_NR_munlock:
ret = get_errno(munlock(g2h(arg1), arg2));
break;
+#endif
+#ifdef TARGET_NR_mlockall
case TARGET_NR_mlockall:
ret = get_errno(mlockall(arg1));
break;
+#endif
+#ifdef TARGET_NR_munlockall
case TARGET_NR_munlockall:
ret = get_errno(munlockall());
break;
+#endif
case TARGET_NR_truncate:
p = lock_user_string(arg1);
ret = get_errno(truncate(p, arg2));
@@ -2805,10 +2958,11 @@
case TARGET_NR_ioperm:
goto unimplemented;
#endif
+#ifdef TARGET_NR_socketcall
case TARGET_NR_socketcall:
ret = do_socketcall(arg1, arg2);
break;
-
+#endif
#ifdef TARGET_NR_accept
case TARGET_NR_accept:
ret = do_accept(arg1, arg2, arg3);
@@ -2846,12 +3000,12 @@
#endif
#ifdef TARGET_NR_recv
case TARGET_NR_recv:
- ret = do_recvfrom(arg1, arg1, arg3, arg4, 0, 0);
+ ret = do_recvfrom(arg1, arg2, arg3, arg4, 0, 0);
break;
#endif
#ifdef TARGET_NR_recvfrom
case TARGET_NR_recvfrom:
- ret = do_recvfrom(arg1, arg1, arg3, arg4, arg5, arg6);
+ ret = do_recvfrom(arg1, arg2, arg3, arg4, arg5, arg6);
break;
#endif
#ifdef TARGET_NR_recvmsg
@@ -2894,9 +3048,13 @@
ret = do_setsockopt(arg1, arg2, arg3, arg4, (socklen_t) arg5);
break;
#endif
-
+
case TARGET_NR_syslog:
- goto unimplemented;
+ p = lock_user_string(arg2);
+ ret = get_errno(sys_syslog((int)arg1, p, (int)arg3));
+ unlock_user(p, arg2, 0);
+ break;
+
case TARGET_NR_setitimer:
{
struct itimerval value, ovalue, *pvalue;
@@ -3013,11 +3171,13 @@
}
}
break;
+#ifdef TARGET_NR_swapoff
case TARGET_NR_swapoff:
p = lock_user_string(arg1);
ret = get_errno(swapoff(p));
unlock_user(p, arg1, 0);
break;
+#endif
case TARGET_NR_sysinfo:
{
struct target_sysinfo *target_value;
@@ -3045,9 +3205,11 @@
}
}
break;
+#ifdef TARGET_NR_ipc
case TARGET_NR_ipc:
ret = do_ipc(arg1, arg2, arg3, arg4, arg5, arg6);
break;
+#endif
case TARGET_NR_fsync:
ret = get_errno(fsync(arg1));
break;
@@ -3088,18 +3250,24 @@
case TARGET_NR_modify_ldt:
ret = get_errno(do_modify_ldt(cpu_env, arg1, arg2, arg3));
break;
+#if !defined(TARGET_X86_64)
case TARGET_NR_vm86old:
goto unimplemented;
case TARGET_NR_vm86:
ret = do_vm86(cpu_env, arg1, arg2);
break;
#endif
+#endif
case TARGET_NR_adjtimex:
goto unimplemented;
+#ifdef TARGET_NR_create_module
case TARGET_NR_create_module:
+#endif
case TARGET_NR_init_module:
case TARGET_NR_delete_module:
+#ifdef TARGET_NR_get_kernel_syms
case TARGET_NR_get_kernel_syms:
+#endif
goto unimplemented;
case TARGET_NR_quotactl:
goto unimplemented;
@@ -3109,15 +3277,22 @@
case TARGET_NR_fchdir:
ret = get_errno(fchdir(arg1));
break;
+#ifdef TARGET_NR_bdflush /* not on x86_64 */
case TARGET_NR_bdflush:
goto unimplemented;
+#endif
+#ifdef TARGET_NR_sysfs
case TARGET_NR_sysfs:
goto unimplemented;
+#endif
case TARGET_NR_personality:
ret = get_errno(personality(arg1));
break;
+#ifdef TARGET_NR_afs_syscall
case TARGET_NR_afs_syscall:
goto unimplemented;
+#endif
+#ifdef TARGET_NR__llseek /* Not on alpha */
case TARGET_NR__llseek:
{
#if defined (__x86_64__)
@@ -3130,6 +3305,7 @@
#endif
}
break;
+#endif
case TARGET_NR_getdents:
#if TARGET_LONG_SIZE != 4
goto unimplemented;
@@ -3169,7 +3345,7 @@
strncpy(tde->d_name, de->d_name, tnamelen);
de = (struct dirent *)((char *)de + reclen);
len -= reclen;
- tde = (struct dirent *)((char *)tde + treclen);
+ tde = (struct target_dirent *)((char *)tde + treclen);
count1 += treclen;
}
ret = count1;
@@ -3231,9 +3407,12 @@
}
break;
#endif /* TARGET_NR_getdents64 */
+#ifdef TARGET_NR__newselect
case TARGET_NR__newselect:
ret = do_select(arg1, arg2, arg3, arg4, arg5);
break;
+#endif
+#ifdef TARGET_NR_poll
case TARGET_NR_poll:
{
struct target_pollfd *target_pfd;
@@ -3259,6 +3438,7 @@
unlock_user(target_pfd, arg1, ret);
}
break;
+#endif
case TARGET_NR_flock:
/* NOTE: the flock constant seems to be the same for every
Linux platform */
@@ -3289,9 +3469,11 @@
case TARGET_NR_getsid:
ret = get_errno(getsid(arg1));
break;
+#if defined(TARGET_NR_fdatasync) /* Not on alpha (osf_datasync ?) */
case TARGET_NR_fdatasync:
ret = get_errno(fdatasync(arg1));
break;
+#endif
case TARGET_NR__sysctl:
/* We don't implement this, but ENODIR is always a safe
return value. */
@@ -3360,12 +3542,30 @@
}
}
break;
+#ifdef TARGET_NR_query_module
case TARGET_NR_query_module:
goto unimplemented;
+#endif
+#ifdef TARGET_NR_nfsservctl
case TARGET_NR_nfsservctl:
goto unimplemented;
+#endif
case TARGET_NR_prctl:
- goto unimplemented;
+ switch (arg1)
+ {
+ case PR_GET_PDEATHSIG:
+ {
+ int deathsig;
+ ret = get_errno(prctl(arg1, &deathsig, arg3, arg4, arg5));
+ if (!is_error(ret) && arg2)
+ tput32(arg2, deathsig);
+ }
+ break;
+ default:
+ ret = get_errno(prctl(arg1, arg2, arg3, arg4, arg5));
+ break;
+ }
+ break;
#ifdef TARGET_NR_pread
case TARGET_NR_pread:
page_unprotect_range(arg2, arg3);
@@ -3784,15 +3984,51 @@
#if TARGET_LONG_BITS == 32
case TARGET_NR_fcntl64:
{
+ int cmd;
struct flock64 fl;
struct target_flock64 *target_fl;
#ifdef TARGET_ARM
struct target_eabi_flock64 *target_efl;
#endif
+ switch(arg2){
+ case TARGET_F_GETLK64:
+ cmd = F_GETLK64;
+ break;
+ case TARGET_F_SETLK64:
+ cmd = F_SETLK64;
+ break;
+ case TARGET_F_SETLKW64:
+ cmd = F_SETLK64;
+ break;
+ default:
+ cmd = arg2;
+ break;
+ }
+
switch(arg2) {
- case F_GETLK64:
- ret = get_errno(fcntl(arg1, arg2, &fl));
+ case TARGET_F_GETLK64:
+#ifdef TARGET_ARM
+ if (((CPUARMState *)cpu_env)->eabi) {
+ lock_user_struct(target_efl, arg3, 1);
+ fl.l_type = tswap16(target_efl->l_type);
+ fl.l_whence = tswap16(target_efl->l_whence);
+ fl.l_start = tswap64(target_efl->l_start);
+ fl.l_len = tswap64(target_efl->l_len);
+ fl.l_pid = tswapl(target_efl->l_pid);
+ unlock_user_struct(target_efl, arg3, 0);
+ } else
+#endif
+ {
+ lock_user_struct(target_fl, arg3, 1);
+ fl.l_type = tswap16(target_fl->l_type);
+ fl.l_whence = tswap16(target_fl->l_whence);
+ fl.l_start = tswap64(target_fl->l_start);
+ fl.l_len = tswap64(target_fl->l_len);
+ fl.l_pid = tswapl(target_fl->l_pid);
+ unlock_user_struct(target_fl, arg3, 0);
+ }
+ ret = get_errno(fcntl(arg1, cmd, &fl));
if (ret == 0) {
#ifdef TARGET_ARM
if (((CPUARMState *)cpu_env)->eabi) {
@@ -3817,8 +4053,8 @@
}
break;
- case F_SETLK64:
- case F_SETLKW64:
+ case TARGET_F_SETLK64:
+ case TARGET_F_SETLKW64:
#ifdef TARGET_ARM
if (((CPUARMState *)cpu_env)->eabi) {
lock_user_struct(target_efl, arg3, 1);
@@ -3839,10 +4075,10 @@
fl.l_pid = tswapl(target_fl->l_pid);
unlock_user_struct(target_fl, arg3, 0);
}
- ret = get_errno(fcntl(arg1, arg2, &fl));
+ ret = get_errno(fcntl(arg1, cmd, &fl));
break;
default:
- ret = get_errno(do_fcntl(arg1, arg2, arg3));
+ ret = get_errno(do_fcntl(arg1, cmd, arg3));
break;
}
break;
@@ -3866,8 +4102,10 @@
case TARGET_NR_gettid:
ret = get_errno(gettid());
break;
+#ifdef TARGET_NR_readahead
case TARGET_NR_readahead:
goto unimplemented;
+#endif
#ifdef TARGET_NR_setxattr
case TARGET_NR_setxattr:
case TARGET_NR_lsetxattr:
@@ -3885,6 +4123,15 @@
#endif
#ifdef TARGET_NR_set_thread_area
case TARGET_NR_set_thread_area:
+#ifdef TARGET_MIPS
+ ((CPUMIPSState *) cpu_env)->tls_value = arg1;
+ ret = 0;
+ break;
+#else
+ goto unimplemented_nowarn;
+#endif
+#endif
+#ifdef TARGET_NR_get_thread_area
case TARGET_NR_get_thread_area:
goto unimplemented_nowarn;
#endif
@@ -3892,10 +4139,40 @@
case TARGET_NR_getdomainname:
goto unimplemented_nowarn;
#endif
+
+#ifdef TARGET_NR_clock_gettime
+ case TARGET_NR_clock_gettime:
+ {
+ struct timespec ts;
+ ret = get_errno(clock_gettime(arg1, &ts));
+ if (!is_error(ret)) {
+ host_to_target_timespec(arg2, &ts);
+ }
+ break;
+ }
+#endif
+#ifdef TARGET_NR_clock_getres
+ case TARGET_NR_clock_getres:
+ {
+ struct timespec ts;
+ ret = get_errno(clock_getres(arg1, &ts));
+ if (!is_error(ret)) {
+ host_to_target_timespec(arg2, &ts);
+ }
+ break;
+ }
+#endif
+
+#if defined(TARGET_NR_set_tid_address) && defined(__NR_set_tid_address)
+ case TARGET_NR_set_tid_address:
+ ret = get_errno(set_tid_address((int *) arg1));
+ break;
+#endif
+
default:
unimplemented:
gemu_log("qemu: Unsupported syscall: %d\n", num);
-#if defined(TARGET_NR_setxattr) || defined(TARGET_NR_set_thread_area) || defined(TARGET_NR_getdomainname)
+#if defined(TARGET_NR_setxattr) || defined(TARGET_NR_get_thread_area) || defined(TARGET_NR_getdomainname)
unimplemented_nowarn:
#endif
ret = -ENOSYS;
Modified: trunk/src/host/qemu-neo1973/linux-user/syscall_defs.h
===================================================================
--- trunk/src/host/qemu-neo1973/linux-user/syscall_defs.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/linux-user/syscall_defs.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -49,7 +49,7 @@
#define TARGET_IOC_TYPEBITS 8
#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SH4) \
- || defined(TARGET_M68K)
+ || defined(TARGET_M68K) || defined(TARGET_ALPHA)
#define TARGET_IOC_SIZEBITS 14
#define TARGET_IOC_DIRBITS 2
@@ -294,7 +294,7 @@
int do_sigaction(int sig, const struct target_sigaction *act,
struct target_sigaction *oact);
-#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_MIPS) || defined (TARGET_SH4) || defined(TARGET_M68K)
+#if defined(TARGET_I386) || defined(TARGET_ARM) || defined(TARGET_SPARC) || defined(TARGET_PPC) || defined(TARGET_MIPS) || defined (TARGET_SH4) || defined(TARGET_M68K) || defined(TARGET_ALPHA)
#if defined(TARGET_SPARC)
#define TARGET_SA_NOCLDSTOP 8u
@@ -1203,6 +1203,50 @@
int64_t st_blocks;
};
+
+#elif defined(TARGET_ALPHA)
+
+struct target_stat {
+ unsigned int st_dev;
+ unsigned int st_ino;
+ unsigned int st_mode;
+ unsigned int st_nlink;
+ unsigned int st_uid;
+ unsigned int st_gid;
+ unsigned int st_rdev;
+ target_long st_size;
+ target_ulong target_st_atime;
+ target_ulong target_st_mtime;
+ target_ulong target_st_ctime;
+ unsigned int st_blksize;
+ unsigned int st_blocks;
+ unsigned int st_flags;
+ unsigned int st_gen;
+};
+
+struct target_stat64 {
+ target_ulong st_dev;
+ target_ulong st_ino;
+ target_ulong st_rdev;
+ target_long st_size;
+ target_ulong st_blocks;
+
+ unsigned int st_mode;
+ unsigned int st_uid;
+ unsigned int st_gid;
+ unsigned int st_blksize;
+ unsigned int st_nlink;
+ unsigned int __pad0;
+
+ target_ulong target_st_atime;
+ target_ulong target_st_atime_nsec;
+ target_ulong target_st_mtime;
+ target_ulong target_st_mtime_nsec;
+ target_ulong target_st_ctime;
+ target_ulong target_st_ctime_nsec;
+ target_long __unused[3];
+};
+
#else
#error unsupported CPU
#endif
Added: trunk/src/host/qemu-neo1973/linux-user/x86_64/syscall.h
===================================================================
--- trunk/src/host/qemu-neo1973/linux-user/x86_64/syscall.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/linux-user/x86_64/syscall.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,92 @@
+#define __USER_CS (0x33)
+#define __USER_DS (0x2B)
+
+struct target_pt_regs {
+ target_ulong r15;
+ target_ulong r14;
+ target_ulong r13;
+ target_ulong r12;
+ target_ulong rbp;
+ target_ulong rbx;
+/* arguments: non interrupts/non tracing syscalls only save upto here*/
+ target_ulong r11;
+ target_ulong r10;
+ target_ulong r9;
+ target_ulong r8;
+ target_ulong rax;
+ target_ulong rcx;
+ target_ulong rdx;
+ target_ulong rsi;
+ target_ulong rdi;
+ target_ulong orig_rax;
+/* end of arguments */
+/* cpu exception frame or undefined */
+ target_ulong rip;
+ target_ulong cs;
+ target_ulong eflags;
+ target_ulong rsp;
+ target_ulong ss;
+/* top of stack page */
+};
+
+/* Maximum number of LDT entries supported. */
+#define TARGET_LDT_ENTRIES 8192
+/* The size of each LDT entry. */
+#define TARGET_LDT_ENTRY_SIZE 8
+
+#define TARGET_GDT_ENTRY_TLS_ENTRIES 3
+#define TARGET_GDT_ENTRY_TLS_MIN 12
+#define TARGET_GDT_ENTRY_TLS_MAX 14
+
+#if 0 // Redefine this
+struct target_modify_ldt_ldt_s {
+ unsigned int entry_number;
+ target_ulong base_addr;
+ unsigned int limit;
+ unsigned int seg_32bit:1;
+ unsigned int contents:2;
+ unsigned int read_exec_only:1;
+ unsigned int limit_in_pages:1;
+ unsigned int seg_not_present:1;
+ unsigned int useable:1;
+ unsigned int lm:1;
+};
+#else
+struct target_modify_ldt_ldt_s {
+ unsigned int entry_number;
+ target_ulong base_addr;
+ unsigned int limit;
+ unsigned int flags;
+};
+#endif
+
+struct target_ipc64_perm
+{
+ int key;
+ uint32_t uid;
+ uint32_t gid;
+ uint32_t cuid;
+ uint32_t cgid;
+ unsigned short mode;
+ unsigned short __pad1;
+ unsigned short seq;
+ unsigned short __pad2;
+ target_ulong __unused1;
+ target_ulong __unused2;
+};
+
+struct target_msqid64_ds {
+ struct target_ipc64_perm msg_perm;
+ unsigned int msg_stime; /* last msgsnd time */
+ unsigned int msg_rtime; /* last msgrcv time */
+ unsigned int msg_ctime; /* last change time */
+ target_ulong msg_cbytes; /* current number of bytes on queue */
+ target_ulong msg_qnum; /* number of messages in queue */
+ target_ulong msg_qbytes; /* max number of bytes on queue */
+ unsigned int msg_lspid; /* pid of last msgsnd */
+ unsigned int msg_lrpid; /* last receive pid */
+ target_ulong __unused4;
+ target_ulong __unused5;
+};
+
+#define UNAME_MACHINE "x86_64"
Added: trunk/src/host/qemu-neo1973/linux-user/x86_64/syscall_nr.h
===================================================================
--- trunk/src/host/qemu-neo1973/linux-user/x86_64/syscall_nr.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/linux-user/x86_64/syscall_nr.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,280 @@
+#define TARGET_NR_read 0
+#define TARGET_NR_write 1
+#define TARGET_NR_open 2
+#define TARGET_NR_close 3
+#define TARGET_NR_stat 4
+#define TARGET_NR_fstat 5
+#define TARGET_NR_lstat 6
+#define TARGET_NR_poll 7
+#define TARGET_NR_lseek 8
+#define TARGET_NR_mmap 9
+#define TARGET_NR_mprotect 10
+#define TARGET_NR_munmap 11
+#define TARGET_NR_brk 12
+#define TARGET_NR_rt_sigaction 13
+#define TARGET_NR_rt_sigprocmask 14
+#define TARGET_NR_rt_sigreturn 15
+#define TARGET_NR_ioctl 16
+#define TARGET_NR_pread64 17
+#define TARGET_NR_pwrite64 18
+#define TARGET_NR_readv 19
+#define TARGET_NR_writev 20
+#define TARGET_NR_access 21
+#define TARGET_NR_pipe 22
+#define TARGET_NR_select 23
+#define TARGET_NR_sched_yield 24
+#define TARGET_NR_mremap 25
+#define TARGET_NR_msync 26
+#define TARGET_NR_mincore 27
+#define TARGET_NR_madvise 28
+#define TARGET_NR_shmget 29
+#define TARGET_NR_shmat 30
+#define TARGET_NR_shmctl 31
+#define TARGET_NR_dup 32
+#define TARGET_NR_dup2 33
+#define TARGET_NR_pause 34
+#define TARGET_NR_nanosleep 35
+#define TARGET_NR_getitimer 36
+#define TARGET_NR_alarm 37
+#define TARGET_NR_setitimer 38
+#define TARGET_NR_getpid 39
+#define TARGET_NR_sendfile 40
+#define TARGET_NR_socket 41
+#define TARGET_NR_connect 42
+#define TARGET_NR_accept 43
+#define TARGET_NR_sendto 44
+#define TARGET_NR_recvfrom 45
+#define TARGET_NR_sendmsg 46
+#define TARGET_NR_recvmsg 47
+#define TARGET_NR_shutdown 48
+#define TARGET_NR_bind 49
+#define TARGET_NR_listen 50
+#define TARGET_NR_getsockname 51
+#define TARGET_NR_getpeername 52
+#define TARGET_NR_socketpair 53
+#define TARGET_NR_setsockopt 54
+#define TARGET_NR_getsockopt 55
+#define TARGET_NR_clone 56
+#define TARGET_NR_fork 57
+#define TARGET_NR_vfork 58
+#define TARGET_NR_execve 59
+#define TARGET_NR_exit 60
+#define TARGET_NR_wait4 61
+#define TARGET_NR_kill 62
+#define TARGET_NR_uname 63
+#define TARGET_NR_semget 64
+#define TARGET_NR_semop 65
+#define TARGET_NR_semctl 66
+#define TARGET_NR_shmdt 67
+#define TARGET_NR_msgget 68
+#define TARGET_NR_msgsnd 69
+#define TARGET_NR_msgrcv 70
+#define TARGET_NR_msgctl 71
+#define TARGET_NR_fcntl 72
+#define TARGET_NR_flock 73
+#define TARGET_NR_fsync 74
+#define TARGET_NR_fdatasync 75
+#define TARGET_NR_truncate 76
+#define TARGET_NR_ftruncate 77
+#define TARGET_NR_getdents 78
+#define TARGET_NR_getcwd 79
+#define TARGET_NR_chdir 80
+#define TARGET_NR_fchdir 81
+#define TARGET_NR_rename 82
+#define TARGET_NR_mkdir 83
+#define TARGET_NR_rmdir 84
+#define TARGET_NR_creat 85
+#define TARGET_NR_link 86
+#define TARGET_NR_unlink 87
+#define TARGET_NR_symlink 88
+#define TARGET_NR_readlink 89
+#define TARGET_NR_chmod 90
+#define TARGET_NR_fchmod 91
+#define TARGET_NR_chown 92
+#define TARGET_NR_fchown 93
+#define TARGET_NR_lchown 94
+#define TARGET_NR_umask 95
+#define TARGET_NR_gettimeofday 96
+#define TARGET_NR_getrlimit 97
+#define TARGET_NR_getrusage 98
+#define TARGET_NR_sysinfo 99
+#define TARGET_NR_times 100
+#define TARGET_NR_ptrace 101
+#define TARGET_NR_getuid 102
+#define TARGET_NR_syslog 103
+#define TARGET_NR_getgid 104
+#define TARGET_NR_setuid 105
+#define TARGET_NR_setgid 106
+#define TARGET_NR_geteuid 107
+#define TARGET_NR_getegid 108
+#define TARGET_NR_setpgid 109
+#define TARGET_NR_getppid 110
+#define TARGET_NR_getpgrp 111
+#define TARGET_NR_setsid 112
+#define TARGET_NR_setreuid 113
+#define TARGET_NR_setregid 114
+#define TARGET_NR_getgroups 115
+#define TARGET_NR_setgroups 116
+#define TARGET_NR_setresuid 117
+#define TARGET_NR_getresuid 118
+#define TARGET_NR_setresgid 119
+#define TARGET_NR_getresgid 120
+#define TARGET_NR_getpgid 121
+#define TARGET_NR_setfsuid 122
+#define TARGET_NR_setfsgid 123
+#define TARGET_NR_getsid 124
+#define TARGET_NR_capget 125
+#define TARGET_NR_capset 126
+#define TARGET_NR_rt_sigpending 127
+#define TARGET_NR_rt_sigtimedwait 128
+#define TARGET_NR_rt_sigqueueinfo 129
+#define TARGET_NR_rt_sigsuspend 130
+#define TARGET_NR_sigaltstack 131
+#define TARGET_NR_utime 132
+#define TARGET_NR_mknod 133
+#define TARGET_NR_uselib 134
+#define TARGET_NR_personality 135
+#define TARGET_NR_ustat 136
+#define TARGET_NR_statfs 137
+#define TARGET_NR_fstatfs 138
+#define TARGET_NR_sysfs 139
+#define TARGET_NR_getpriority 140
+#define TARGET_NR_setpriority 141
+#define TARGET_NR_sched_setparam 142
+#define TARGET_NR_sched_getparam 143
+#define TARGET_NR_sched_setscheduler 144
+#define TARGET_NR_sched_getscheduler 145
+#define TARGET_NR_sched_get_priority_max 146
+#define TARGET_NR_sched_get_priority_min 147
+#define TARGET_NR_sched_rr_get_interval 148
+#define TARGET_NR_mlock 149
+#define TARGET_NR_munlock 150
+#define TARGET_NR_mlockall 151
+#define TARGET_NR_munlockall 152
+#define TARGET_NR_vhangup 153
+#define TARGET_NR_modify_ldt 154
+#define TARGET_NR_pivot_root 155
+#define TARGET_NR__sysctl 156
+#define TARGET_NR_prctl 157
+#define TARGET_NR_arch_prctl 158
+#define TARGET_NR_adjtimex 159
+#define TARGET_NR_setrlimit 160
+#define TARGET_NR_chroot 161
+#define TARGET_NR_sync 162
+#define TARGET_NR_acct 163
+#define TARGET_NR_settimeofday 164
+#define TARGET_NR_mount 165
+#define TARGET_NR_umount2 166
+#define TARGET_NR_swapon 167
+#define TARGET_NR_swapoff 168
+#define TARGET_NR_reboot 169
+#define TARGET_NR_sethostname 170
+#define TARGET_NR_setdomainname 171
+#define TARGET_NR_iopl 172
+#define TARGET_NR_ioperm 173
+#define TARGET_NR_create_module 174
+#define TARGET_NR_init_module 175
+#define TARGET_NR_delete_module 176
+#define TARGET_NR_get_kernel_syms 177
+#define TARGET_NR_query_module 178
+#define TARGET_NR_quotactl 179
+#define TARGET_NR_nfsservctl 180
+#define TARGET_NR_getpmsg 181 /* reserved for LiS/STREAMS */
+#define TARGET_NR_putpmsg 182 /* reserved for LiS/STREAMS */
+#define TARGET_NR_afs_syscall 183 /* reserved for AFS */
+#define TARGET_NR_tuxcall 184 /* reserved for tux */
+#define TARGET_NR_security 185
+#define TARGET_NR_gettid 186
+#define TARGET_NR_readahead 187
+#define TARGET_NR_setxattr 188
+#define TARGET_NR_lsetxattr 189
+#define TARGET_NR_fsetxattr 190
+#define TARGET_NR_getxattr 191
+#define TARGET_NR_lgetxattr 192
+#define TARGET_NR_fgetxattr 193
+#define TARGET_NR_listxattr 194
+#define TARGET_NR_llistxattr 195
+#define TARGET_NR_flistxattr 196
+#define TARGET_NR_removexattr 197
+#define TARGET_NR_lremovexattr 198
+#define TARGET_NR_fremovexattr 199
+#define TARGET_NR_tkill 200
+#define TARGET_NR_time 201
+#define TARGET_NR_futex 202
+#define TARGET_NR_sched_setaffinity 203
+#define TARGET_NR_sched_getaffinity 204
+#define TARGET_NR_set_thread_area 205
+#define TARGET_NR_io_setup 206
+#define TARGET_NR_io_destroy 207
+#define TARGET_NR_io_getevents 208
+#define TARGET_NR_io_submit 209
+#define TARGET_NR_io_cancel 210
+#define TARGET_NR_get_thread_area 211
+#define TARGET_NR_lookup_dcookie 212
+#define TARGET_NR_epoll_create 213
+#define TARGET_NR_epoll_ctl_old 214
+#define TARGET_NR_epoll_wait_old 215
+#define TARGET_NR_remap_file_pages 216
+#define TARGET_NR_getdents64 217
+#define TARGET_NR_set_tid_address 218
+#define TARGET_NR_restart_syscall 219
+#define TARGET_NR_semtimedop 220
+#define TARGET_NR_fadvise64 221
+#define TARGET_NR_timer_create 222
+#define TARGET_NR_timer_settime 223
+#define TARGET_NR_timer_gettime 224
+#define TARGET_NR_timer_getoverrun 225
+#define TARGET_NR_timer_delete 226
+#define TARGET_NR_clock_settime 227
+#define TARGET_NR_clock_gettime 228
+#define TARGET_NR_clock_getres 229
+#define TARGET_NR_clock_nanosleep 230
+#define TARGET_NR_exit_group 231
+#define TARGET_NR_epoll_wait 232
+#define TARGET_NR_epoll_ctl 233
+#define TARGET_NR_tgkill 234
+#define TARGET_NR_utimes 235
+#define TARGET_NR_vserver 236
+#define TARGET_NR_mbind 237
+#define TARGET_NR_set_mempolicy 238
+#define TARGET_NR_get_mempolicy 239
+#define TARGET_NR_mq_open 240
+#define TARGET_NR_mq_unlink 241
+#define TARGET_NR_mq_timedsend 242
+#define TARGET_NR_mq_timedreceive 243
+#define TARGET_NR_mq_notify 244
+#define TARGET_NR_mq_getsetattr 245
+#define TARGET_NR_kexec_load 246
+#define TARGET_NR_waitid 247
+#define TARGET_NR_add_key 248
+#define TARGET_NR_request_key 249
+#define TARGET_NR_keyctl 250
+#define TARGET_NR_ioprio_set 251
+#define TARGET_NR_ioprio_get 252
+#define TARGET_NR_inotify_init 253
+#define TARGET_NR_inotify_add_watch 254
+#define TARGET_NR_inotify_rm_watch 255
+#define TARGET_NR_migrate_pages 256
+#define TARGET_NR_openat 257
+#define TARGET_NR_mkdirat 258
+#define TARGET_NR_mknodat 259
+#define TARGET_NR_fchownat 260
+#define TARGET_NR_futimesat 261
+#define TARGET_NR_newfstatat 262
+#define TARGET_NR_unlinkat 263
+#define TARGET_NR_renameat 264
+#define TARGET_NR_linkat 265
+#define TARGET_NR_symlinkat 266
+#define TARGET_NR_readlinkat 267
+#define TARGET_NR_fchmodat 268
+#define TARGET_NR_faccessat 269
+#define TARGET_NR_pselect6 270
+#define TARGET_NR_ppoll 271
+#define TARGET_NR_unshare 272
+#define TARGET_NR_set_robust_list 273
+#define TARGET_NR_get_robust_list 274
+#define TARGET_NR_splice 275
+#define TARGET_NR_tee 276
+#define TARGET_NR_sync_file_range 277
+#define TARGET_NR_vmsplice 278
+#define TARGET_NR_move_pages 279
Added: trunk/src/host/qemu-neo1973/linux-user/x86_64/termbits.h
===================================================================
--- trunk/src/host/qemu-neo1973/linux-user/x86_64/termbits.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/linux-user/x86_64/termbits.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,247 @@
+#define TARGET_NCCS 19
+
+typedef unsigned char target_cc_t;
+typedef unsigned int target_speed_t;
+typedef unsigned int target_tcflag_t;
+struct target_termios {
+ target_tcflag_t c_iflag; /* input mode flags */
+ target_tcflag_t c_oflag; /* output mode flags */
+ target_tcflag_t c_cflag; /* control mode flags */
+ target_tcflag_t c_lflag; /* local mode flags */
+ target_cc_t c_line; /* line discipline */
+ target_cc_t c_cc[TARGET_NCCS]; /* control characters */
+};
+
+/* c_cc characters */
+#define TARGET_VINTR 0
+#define TARGET_VQUIT 1
+#define TARGET_VERASE 2
+#define TARGET_VKILL 3
+#define TARGET_VEOF 4
+#define TARGET_VTIME 5
+#define TARGET_VMIN 6
+#define TARGET_VSWTC 7
+#define TARGET_VSTART 8
+#define TARGET_VSTOP 9
+#define TARGET_VSUSP 10
+#define TARGET_VEOL 11
+#define TARGET_VREPRINT 12
+#define TARGET_VDISCARD 13
+#define TARGET_VWERASE 14
+#define TARGET_VLNEXT 15
+#define TARGET_VEOL2 16
+
+/* c_iflag bits */
+#define TARGET_IGNBRK 0000001
+#define TARGET_BRKINT 0000002
+#define TARGET_IGNPAR 0000004
+#define TARGET_PARMRK 0000010
+#define TARGET_INPCK 0000020
+#define TARGET_ISTRIP 0000040
+#define TARGET_INLCR 0000100
+#define TARGET_IGNCR 0000200
+#define TARGET_ICRNL 0000400
+#define TARGET_IUCLC 0001000
+#define TARGET_IXON 0002000
+#define TARGET_IXANY 0004000
+#define TARGET_IXOFF 0010000
+#define TARGET_IMAXBEL 0020000
+#define TARGET_IUTF8 0040000
+
+/* c_oflag bits */
+#define TARGET_OPOST 0000001
+#define TARGET_OLCUC 0000002
+#define TARGET_ONLCR 0000004
+#define TARGET_OCRNL 0000010
+#define TARGET_ONOCR 0000020
+#define TARGET_ONLRET 0000040
+#define TARGET_OFILL 0000100
+#define TARGET_OFDEL 0000200
+#define TARGET_NLDLY 0000400
+#define TARGET_NL0 0000000
+#define TARGET_NL1 0000400
+#define TARGET_CRDLY 0003000
+#define TARGET_CR0 0000000
+#define TARGET_CR1 0001000
+#define TARGET_CR2 0002000
+#define TARGET_CR3 0003000
+#define TARGET_TABDLY 0014000
+#define TARGET_TAB0 0000000
+#define TARGET_TAB1 0004000
+#define TARGET_TAB2 0010000
+#define TARGET_TAB3 0014000
+#define TARGET_XTABS 0014000
+#define TARGET_BSDLY 0020000
+#define TARGET_BS0 0000000
+#define TARGET_BS1 0020000
+#define TARGET_VTDLY 0040000
+#define TARGET_VT0 0000000
+#define TARGET_VT1 0040000
+#define TARGET_FFDLY 0100000
+#define TARGET_FF0 0000000
+#define TARGET_FF1 0100000
+
+/* c_cflag bit meaning */
+#define TARGET_CBAUD 0010017
+#define TARGET_B0 0000000 /* hang up */
+#define TARGET_B50 0000001
+#define TARGET_B75 0000002
+#define TARGET_B110 0000003
+#define TARGET_B134 0000004
+#define TARGET_B150 0000005
+#define TARGET_B200 0000006
+#define TARGET_B300 0000007
+#define TARGET_B600 0000010
+#define TARGET_B1200 0000011
+#define TARGET_B1800 0000012
+#define TARGET_B2400 0000013
+#define TARGET_B4800 0000014
+#define TARGET_B9600 0000015
+#define TARGET_B19200 0000016
+#define TARGET_B38400 0000017
+#define TARGET_EXTA B19200
+#define TARGET_EXTB B38400
+#define TARGET_CSIZE 0000060
+#define TARGET_CS5 0000000
+#define TARGET_CS6 0000020
+#define TARGET_CS7 0000040
+#define TARGET_CS8 0000060
+#define TARGET_CSTOPB 0000100
+#define TARGET_CREAD 0000200
+#define TARGET_PARENB 0000400
+#define TARGET_PARODD 0001000
+#define TARGET_HUPCL 0002000
+#define TARGET_CLOCAL 0004000
+#define TARGET_CBAUDEX 0010000
+#define TARGET_BOTHER 0010000 /* non standard rate */
+#define TARGET_B57600 0010001
+#define TARGET_B115200 0010002
+#define TARGET_B230400 0010003
+#define TARGET_B460800 0010004
+#define TARGET_B500000 0010005
+#define TARGET_B576000 0010006
+#define TARGET_B921600 0010007
+#define TARGET_B1000000 0010010
+#define TARGET_B1152000 0010011
+#define TARGET_B1500000 0010012
+#define TARGET_B2000000 0010013
+#define TARGET_B2500000 0010014
+#define TARGET_B3000000 0010015
+#define TARGET_B3500000 0010016
+#define TARGET_B4000000 0010017
+#define TARGET_CIBAUD 002003600000 /* input baud rate */
+#define TARGET_CMSPAR 010000000000 /* mark or space (stick) parity */
+#define TARGET_CRTSCTS 020000000000 /* flow control */
+
+#define TARGET_IBSHIFT 8 /* Shift from CBAUD to CIBAUD */
+
+/* c_lflag bits */
+#define TARGET_ISIG 0000001
+#define TARGET_ICANON 0000002
+#define TARGET_XCASE 0000004
+#define TARGET_ECHO 0000010
+#define TARGET_ECHOE 0000020
+#define TARGET_ECHOK 0000040
+#define TARGET_ECHONL 0000100
+#define TARGET_NOFLSH 0000200
+#define TARGET_TOSTOP 0000400
+#define TARGET_ECHOCTL 0001000
+#define TARGET_ECHOPRT 0002000
+#define TARGET_ECHOKE 0004000
+#define TARGET_FLUSHO 0010000
+#define TARGET_PENDIN 0040000
+#define TARGET_IEXTEN 0100000
+
+/* tcflow() and TCXONC use these */
+#define TARGET_TCOOFF 0
+#define TARGET_TCOON 1
+#define TARGET_TCIOFF 2
+#define TARGET_TCION 3
+
+/* tcflush() and TCFLSH use these */
+#define TARGET_TCIFLUSH 0
+#define TARGET_TCOFLUSH 1
+#define TARGET_TCIOFLUSH 2
+
+/* tcsetattr uses these */
+#define TARGET_TCSANOW 0
+#define TARGET_TCSADRAIN 1
+#define TARGET_TCSAFLUSH 2
+
+#define TARGET_TCGETS 0x5401
+#define TARGET_TCSETS 0x5402
+#define TARGET_TCSETSW 0x5403
+#define TARGET_TCSETSF 0x5404
+#define TARGET_TCGETA 0x5405
+#define TARGET_TCSETA 0x5406
+#define TARGET_TCSETAW 0x5407
+#define TARGET_TCSETAF 0x5408
+#define TARGET_TCSBRK 0x5409
+#define TARGET_TCXONC 0x540A
+#define TARGET_TCFLSH 0x540B
+#define TARGET_TIOCEXCL 0x540C
+#define TARGET_TIOCNXCL 0x540D
+#define TARGET_TIOCSCTTY 0x540E
+#define TARGET_TIOCGPGRP 0x540F
+#define TARGET_TIOCSPGRP 0x5410
+#define TARGET_TIOCOUTQ 0x5411
+#define TARGET_TIOCSTI 0x5412
+#define TARGET_TIOCGWINSZ 0x5413
+#define TARGET_TIOCSWINSZ 0x5414
+#define TARGET_TIOCMGET 0x5415
+#define TARGET_TIOCMBIS 0x5416
+#define TARGET_TIOCMBIC 0x5417
+#define TARGET_TIOCMSET 0x5418
+#define TARGET_TIOCGSOFTCAR 0x5419
+#define TARGET_TIOCSSOFTCAR 0x541A
+#define TARGET_FIONREAD 0x541B
+#define TARGET_TIOCINQ FIONREAD
+#define TARGET_TIOCLINUX 0x541C
+#define TARGET_TIOCCONS 0x541D
+#define TARGET_TIOCGSERIAL 0x541E
+#define TARGET_TIOCSSERIAL 0x541F
+#define TARGET_TIOCPKT 0x5420
+#define TARGET_FIONBIO 0x5421
+#define TARGET_TIOCNOTTY 0x5422
+#define TARGET_TIOCSETD 0x5423
+#define TARGET_TIOCGETD 0x5424
+#define TARGET_TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */
+#define TARGET_TIOCSBRK 0x5427 /* BSD compatibility */
+#define TARGET_TIOCCBRK 0x5428 /* BSD compatibility */
+#define TARGET_TIOCGSID 0x5429 /* Return the session ID of FD */
+#define TARGET_TCGETS2 _IOR('T',0x2A, struct termios2)
+#define TARGET_TCSETS2 _IOW('T',0x2B, struct termios2)
+#define TARGET_TCSETSW2 _IOW('T',0x2C, struct termios2)
+#define TARGET_TCSETSF2 _IOW('T',0x2D, struct termios2)
+#define TARGET_TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */
+#define TARGET_TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */
+
+#define TARGET_FIONCLEX 0x5450 /* these numbers need to be adjusted. */
+#define TARGET_FIOCLEX 0x5451
+#define TARGET_FIOASYNC 0x5452
+#define TARGET_TIOCSERCONFIG 0x5453
+#define TARGET_TIOCSERGWILD 0x5454
+#define TARGET_TIOCSERSWILD 0x5455
+#define TARGET_TIOCGLCKTRMIOS 0x5456
+#define TARGET_TIOCSLCKTRMIOS 0x5457
+#define TARGET_TIOCSERGSTRUCT 0x5458 /* For debugging only */
+#define TARGET_TIOCSERGETLSR 0x5459 /* Get line status register */
+#define TARGET_TIOCSERGETMULTI 0x545A /* Get multiport config */
+#define TARGET_TIOCSERSETMULTI 0x545B /* Set multiport config */
+
+#define TARGET_TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */
+#define TARGET_TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */
+#define TARGET_TIOCGHAYESESP 0x545E /* Get Hayes ESP configuration */
+#define TARGET_TIOCSHAYESESP 0x545F /* Set Hayes ESP configuration */
+#define TARGET_FIOQSIZE 0x5460
+
+/* Used for packet mode */
+#define TARGET_TIOCPKT_DATA 0
+#define TARGET_TIOCPKT_FLUSHREAD 1
+#define TARGET_TIOCPKT_FLUSHWRITE 2
+#define TARGET_TIOCPKT_STOP 4
+#define TARGET_TIOCPKT_START 8
+#define TARGET_TIOCPKT_NOSTOP 16
+#define TARGET_TIOCPKT_DOSTOP 32
+
+#define TARGET_TIOCSER_TEMT 0x01 /* Transmitter physically empty */
Modified: trunk/src/host/qemu-neo1973/loader.c
===================================================================
--- trunk/src/host/qemu-neo1973/loader.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/loader.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -23,6 +23,7 @@
*/
#include "vl.h"
#include "disas.h"
+#include "uboot_image.h"
/* return the size or -1 if error */
int get_image_size(const char *filename)
@@ -195,7 +196,7 @@
/* return < 0 if error, otherwise the number of bytes loaded in memory */
int load_elf(const char *filename, int64_t virt_to_phys_addend,
- uint64_t *pentry)
+ uint64_t *pentry, uint64_t *lowaddr, uint64_t *highaddr)
{
int fd, data_order, host_data_order, must_swab, ret;
uint8_t e_ident[EI_NIDENT];
@@ -229,9 +230,11 @@
lseek(fd, 0, SEEK_SET);
if (e_ident[EI_CLASS] == ELFCLASS64) {
- ret = load_elf64(fd, virt_to_phys_addend, must_swab, pentry);
+ ret = load_elf64(fd, virt_to_phys_addend, must_swab, pentry,
+ lowaddr, highaddr);
} else {
- ret = load_elf32(fd, virt_to_phys_addend, must_swab, pentry);
+ ret = load_elf32(fd, virt_to_phys_addend, must_swab, pentry,
+ lowaddr, highaddr);
}
close(fd);
@@ -241,3 +244,80 @@
close(fd);
return -1;
}
+
+static void bswap_uboot_header(uboot_image_header_t *hdr)
+{
+#ifndef WORDS_BIGENDIAN
+ bswap32s(&hdr->ih_magic);
+ bswap32s(&hdr->ih_hcrc);
+ bswap32s(&hdr->ih_time);
+ bswap32s(&hdr->ih_size);
+ bswap32s(&hdr->ih_load);
+ bswap32s(&hdr->ih_ep);
+ bswap32s(&hdr->ih_dcrc);
+#endif
+}
+
+/* Load a U-Boot image. */
+int load_uboot(const char *filename, target_ulong *ep, int *is_linux)
+{
+
+ int fd;
+ int size;
+ uboot_image_header_t h;
+ uboot_image_header_t *hdr = &h;
+ uint8_t *data = NULL;
+
+ fd = open(filename, O_RDONLY | O_BINARY);
+ if (fd < 0)
+ return -1;
+
+ size = read(fd, hdr, sizeof(uboot_image_header_t));
+ if (size < 0)
+ goto fail;
+
+ bswap_uboot_header(hdr);
+
+ if (hdr->ih_magic != IH_MAGIC)
+ goto fail;
+
+ /* TODO: Implement Multi-File images. */
+ if (hdr->ih_type == IH_TYPE_MULTI) {
+ fprintf(stderr, "Unable to load multi-file u-boot images\n");
+ goto fail;
+ }
+
+ /* TODO: Implement compressed images. */
+ if (hdr->ih_comp != IH_COMP_NONE) {
+ fprintf(stderr, "Unable to load compressed u-boot images\n");
+ goto fail;
+ }
+
+ /* TODO: Check CPU type. */
+ if (is_linux) {
+ if (hdr->ih_type == IH_TYPE_KERNEL && hdr->ih_os == IH_OS_LINUX)
+ *is_linux = 1;
+ else
+ *is_linux = 0;
+ }
+
+ *ep = hdr->ih_ep;
+ data = qemu_malloc(hdr->ih_size);
+ if (!data)
+ goto fail;
+
+ if (read(fd, data, hdr->ih_size) != hdr->ih_size) {
+ fprintf(stderr, "Error reading file\n");
+ goto fail;
+ }
+
+ cpu_physical_memory_write_rom(hdr->ih_load, data, hdr->ih_size);
+
+ return hdr->ih_size;
+
+fail:
+ if (data)
+ qemu_free(data);
+ close(fd);
+ return -1;
+}
Modified: trunk/src/host/qemu-neo1973/monitor.c
===================================================================
--- trunk/src/host/qemu-neo1973/monitor.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/monitor.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -54,7 +54,8 @@
const char *help;
} term_cmd_t;
-static CharDriverState *monitor_hd;
+#define MAX_MON 4
+static CharDriverState *monitor_hd[MAX_MON];
static int hide_banner;
static term_cmd_t term_cmds[];
@@ -69,8 +70,11 @@
void term_flush(void)
{
+ int i;
if (term_outbuf_index > 0) {
- qemu_chr_write(monitor_hd, term_outbuf, term_outbuf_index);
+ for (i = 0; i < MAX_MON; i++)
+ if (monitor_hd[i] && monitor_hd[i]->focus == 0)
+ qemu_chr_write(monitor_hd[i], term_outbuf, term_outbuf_index);
term_outbuf_index = 0;
}
}
@@ -231,6 +235,12 @@
term_printf("%s\n", QEMU_VERSION);
}
+static void do_info_name(void)
+{
+ if (qemu_name)
+ term_printf("%s\n", qemu_name);
+}
+
static void do_info_block(void)
{
bdrv_info();
@@ -327,6 +337,17 @@
}
}
+#if defined(TARGET_PPC)
+/* XXX: not implemented in other targets */
+static void do_info_cpu_stats (void)
+{
+ CPUState *env;
+
+ env = mon_get_cpu();
+ cpu_dump_statistics(env, NULL, &monitor_fprintf, 0);
+}
+#endif
+
static void do_quit(void)
{
exit(0);
@@ -409,14 +430,14 @@
}
#ifdef CONFIG_GDBSTUB
-static void do_gdbserver(int has_port, int port)
+static void do_gdbserver(const char *port)
{
- if (!has_port)
+ if (!port)
port = DEFAULT_GDBSTUB_PORT;
if (gdbserver_start(port) < 0) {
- qemu_printf("Could not open gdbserver socket on port %d\n", port);
+ qemu_printf("Could not open gdbserver socket on port '%s'\n", port);
} else {
- qemu_printf("Waiting gdb connection on port %d\n", port);
+ qemu_printf("Waiting gdb connection on port '%s'\n", port);
}
}
#endif
@@ -1184,9 +1205,9 @@
{ "q|quit", "", do_quit,
"", "quit the emulator" },
{ "eject", "-fB", do_eject,
- "[-f] device", "eject a removable media (use -f to force it)" },
+ "[-f] device", "eject a removable medium (use -f to force it)" },
{ "change", "BF", do_change,
- "device filename", "change a removable media" },
+ "device filename", "change a removable medium" },
{ "screendump", "F", do_screen_dump,
"filename", "save screen into PPM image 'filename'" },
{ "log", "s", do_log,
@@ -1202,7 +1223,7 @@
{ "c|cont", "", do_cont,
"", "resume emulation", },
#ifdef CONFIG_GDBSTUB
- { "gdbserver", "i?", do_gdbserver,
+ { "gdbserver", "s?", do_gdbserver,
"[port]", "start gdbserver session (default port=1234)", },
#endif
{ "x", "/l", do_memory_dump,
@@ -1291,6 +1312,14 @@
"", "show guest PCMCIA status" },
{ "mice", "", do_info_mice,
"", "show which guest mouse is receiving events" },
+ { "vnc", "", do_info_vnc,
+ "", "show the vnc server status"},
+ { "name", "", do_info_name,
+ "", "show the current VM name" },
+#if defined(TARGET_PPC)
+ { "cpustats", "", do_info_cpu_stats,
+ "", "show CPU statistics", },
+#endif
{ NULL, NULL, },
};
@@ -2081,9 +2110,9 @@
}
if (nb_args + 3 > MAX_ARGS)
goto error_args;
- args[nb_args++] = (void*)count;
- args[nb_args++] = (void*)format;
- args[nb_args++] = (void*)size;
+ args[nb_args++] = (void*)(long)count;
+ args[nb_args++] = (void*)(long)format;
+ args[nb_args++] = (void*)(long)size;
}
break;
case 'i':
@@ -2111,7 +2140,7 @@
typestr++;
if (nb_args >= MAX_ARGS)
goto error_args;
- args[nb_args++] = (void *)has_arg;
+ args[nb_args++] = (void *)(long)has_arg;
if (!has_arg) {
if (nb_args >= MAX_ARGS)
goto error_args;
@@ -2125,16 +2154,16 @@
if (c == 'i') {
if (nb_args >= MAX_ARGS)
goto error_args;
- args[nb_args++] = (void *)(int)val;
+ args[nb_args++] = (void *)(long)val;
} else {
if ((nb_args + 1) >= MAX_ARGS)
goto error_args;
#if TARGET_LONG_BITS == 64
- args[nb_args++] = (void *)(int)((val >> 32) & 0xffffffff);
+ args[nb_args++] = (void *)(long)((val >> 32) & 0xffffffff);
#else
args[nb_args++] = (void *)0;
#endif
- args[nb_args++] = (void *)(int)(val & 0xffffffff);
+ args[nb_args++] = (void *)(long)(val & 0xffffffff);
}
}
break;
@@ -2161,7 +2190,7 @@
}
if (nb_args >= MAX_ARGS)
goto error_args;
- args[nb_args++] = (void *)has_option;
+ args[nb_args++] = (void *)(long)has_option;
}
break;
default:
@@ -2444,13 +2473,28 @@
monitor_start_input();
}
+static int is_first_init = 1;
+
void monitor_init(CharDriverState *hd, int show_banner)
{
- monitor_hd = hd;
+ int i;
+
+ if (is_first_init) {
+ for (i = 0; i < MAX_MON; i++) {
+ monitor_hd[i] = NULL;
+ }
+ is_first_init = 0;
+ }
+ for (i = 0; i < MAX_MON; i++) {
+ if (monitor_hd[i] == NULL) {
+ monitor_hd[i] = hd;
+ break;
+ }
+ }
+
hide_banner = !show_banner;
- qemu_chr_add_read_handler(hd, term_can_read, term_read, NULL);
- qemu_chr_add_event_handler(hd, term_event);
+ qemu_chr_add_handlers(hd, term_can_read, term_read, term_event, NULL);
}
/* XXX: use threads ? */
@@ -2468,8 +2512,12 @@
void monitor_readline(const char *prompt, int is_password,
char *buf, int buf_size)
{
+ int i;
+
if (is_password) {
- qemu_chr_send_event(monitor_hd, CHR_EVENT_FOCUS);
+ for (i = 0; i < MAX_MON; i++)
+ if (monitor_hd[i] && monitor_hd[i]->focus == 0)
+ qemu_chr_send_event(monitor_hd[i], CHR_EVENT_FOCUS);
}
readline_start(prompt, is_password, monitor_readline_cb, NULL);
monitor_readline_buf = buf;
Modified: trunk/src/host/qemu-neo1973/openmoko/download.sh
===================================================================
--- trunk/src/host/qemu-neo1973/openmoko/download.sh 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/openmoko/download.sh 2007-05-11 23:44:50 UTC (rev 1948)
@@ -34,7 +34,7 @@
${echo} "$name" > .list
fi
done
- export $2=`sort .list | tail -n 1`
+ export $2=`sort -n .list | tail -n 1`
rm -rf .list
[ -z "${!2}" ] && ( ${echo} not found; exit -1 )
${echo} ${!2}
Modified: trunk/src/host/qemu-neo1973/openmoko/flash.sh
===================================================================
--- trunk/src/host/qemu-neo1973/openmoko/flash.sh 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/openmoko/flash.sh 2007-05-11 23:44:50 UTC (rev 1948)
@@ -43,7 +43,7 @@
# We assume they have numeric date or some build number in their names.
most_recent () {
cd $src_dir
- export $2="`basename \`ls -d -1 $img_dir/$1 | sort | tail -n 1\``"
+ export $2="`basename \`ls -d -1 $img_dir/$1 | sort -n | tail -n 1\``"
export $3="`python -c \"import os; print '0x%lx' \
%(os.stat('$img_dir/${!2}').st_size)\"`"
cd $script_dir
Modified: trunk/src/host/qemu-neo1973/osdep.c
===================================================================
--- trunk/src/host/qemu-neo1973/osdep.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/osdep.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -27,6 +27,11 @@
#include <string.h>
#include <errno.h>
#include <unistd.h>
+#include <fcntl.h>
+#ifdef HOST_SOLARIS
+#include <sys/types.h>
+#include <sys/statvfs.h>
+#endif
#include "cpu.h"
#if defined(USE_KQEMU)
@@ -86,13 +91,22 @@
const char *tmpdir;
char phys_ram_file[1024];
void *ptr;
+#ifdef HOST_SOLARIS
+ struct statvfs stfs;
+#else
struct statfs stfs;
+#endif
if (phys_ram_fd < 0) {
tmpdir = getenv("QEMU_TMPDIR");
if (!tmpdir)
+#ifdef HOST_SOLARIS
+ tmpdir = "/tmp";
+ if (statvfs(tmpdir, &stfs) == 0) {
+#else
tmpdir = "/dev/shm";
if (statfs(tmpdir, &stfs) == 0) {
+#endif
int64_t free_space;
int ram_mb;
@@ -203,3 +217,50 @@
strcpy(ptr, str);
return ptr;
}
+
+int qemu_create_pidfile(const char *filename)
+{
+ char buffer[128];
+ int len;
+#ifndef _WIN32
+ int fd;
+
+ fd = open(filename, O_RDWR | O_CREAT, 0600);
+ if (fd == -1)
+ return -1;
+
+ if (lockf(fd, F_TLOCK, 0) == -1)
+ return -1;
+
+ len = snprintf(buffer, sizeof(buffer), "%ld\n", (long)getpid());
+ if (write(fd, buffer, len) != len)
+ return -1;
+#else
+ HANDLE file;
+ DWORD flags;
+ OVERLAPPED overlap;
+ BOOL ret;
+
+ /* Open for writing with no sharing. */
+ file = CreateFile(filename, GENERIC_WRITE, 0, NULL,
+ OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+
+ if (file == INVALID_HANDLE_VALUE)
+ return -1;
+
+ flags = LOCKFILE_EXCLUSIVE_LOCK | LOCKFILE_FAIL_IMMEDIATELY;
+ overlap.hEvent = 0;
+ /* Lock 1 byte. */
+ ret = LockFileEx(file, flags, 0, 0, 1, &overlap);
+ if (ret == 0)
+ return -1;
+
+ /* Write PID to file. */
+ len = snprintf(buffer, sizeof(buffer), "%ld\n", (long)getpid());
+ ret = WriteFileEx(file, (LPCVOID)buffer, (DWORD)len,
+ &overlap, NULL);
+ if (ret == 0)
+ return -1;
+#endif
+ return 0;
+}
Modified: trunk/src/host/qemu-neo1973/osdep.h
===================================================================
--- trunk/src/host/qemu-neo1973/osdep.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/osdep.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -15,4 +15,6 @@
void *get_mmap_addr(unsigned long size);
+int qemu_create_pidfile(const char *filename);
+
#endif
Modified: trunk/src/host/qemu-neo1973/pc-bios/README
===================================================================
--- trunk/src/host/qemu-neo1973/pc-bios/README 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/pc-bios/README 2007-05-11 23:44:50 UTC (rev 1948)
@@ -14,6 +14,8 @@
- OpenBIOS (http://www.openbios.org/) is a free (GPL v2) portable
firmware implementation. The goal is to implement a 100% IEEE
1275-1994 (referred to as Open Firmware) compliant firmware.
+ The included Sparc32 image is built from SVN version 144 and Sparc64
+ image from version 125.
- The PXE roms come from Rom-o-Matic etherboot 5.4.2.
pcnet32:pcnet32 -- [0x1022,0x2000]
Modified: trunk/src/host/qemu-neo1973/pc-bios/bios.bin
===================================================================
(Binary files differ)
Modified: trunk/src/host/qemu-neo1973/pc-bios/bios.diff
===================================================================
--- trunk/src/host/qemu-neo1973/pc-bios/bios.diff 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/pc-bios/bios.diff 2007-05-11 23:44:50 UTC (rev 1948)
@@ -1,3 +1,25 @@
+Index: rombios.c
+===================================================================
+RCS file: /cvsroot/bochs/bochs/bios/rombios.c,v
+retrieving revision 1.174
+diff -u -w -r1.174 rombios.c
+--- rombios.c 17 Oct 2006 16:48:05 -0000 1.174
++++ rombios.c 8 Feb 2007 21:57:48 -0000
+@@ -9472,6 +9472,14 @@
+ mov eax, #0x00040000
+ call eax
+
++ ;; reset the memory (some boot loaders such as syslinux suppose
++ ;; that the memory is set to zero)
++ mov edi, #0x00040000
++ mov ecx, #0x40000 / 4
++ xor eax, eax
++ rep
++ stosd
++
+ ;; return to 16 bit protected mode first
+ db 0xea
+ dd rombios32_10
Index: rombios.h
===================================================================
RCS file: /cvsroot/bochs/bochs/bios/rombios.h,v
@@ -4,7 +26,7 @@
retrieving revision 1.3
diff -u -w -r1.3 rombios.h
--- rombios.h 3 Oct 2006 20:27:30 -0000 1.3
-+++ rombios.h 1 Nov 2006 19:16:34 -0000
++++ rombios.h 8 Feb 2007 21:57:48 -0000
@@ -19,7 +19,7 @@
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
@@ -20,7 +42,7 @@
retrieving revision 1.8
diff -u -w -r1.8 rombios32.c
--- rombios32.c 3 Oct 2006 20:27:30 -0000 1.8
-+++ rombios32.c 1 Nov 2006 19:16:34 -0000
++++ rombios32.c 8 Feb 2007 21:57:48 -0000
@@ -852,6 +852,11 @@
int ioapic_id, i, len;
int mp_config_table_size;
Modified: trunk/src/host/qemu-neo1973/pc-bios/openbios-sparc32
===================================================================
(Binary files differ)
Added: trunk/src/host/qemu-neo1973/pc-bios/openbios-sparc64
===================================================================
(Binary files differ)
Property changes on: trunk/src/host/qemu-neo1973/pc-bios/openbios-sparc64
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Modified: trunk/src/host/qemu-neo1973/ppc.ld
===================================================================
--- trunk/src/host/qemu-neo1973/ppc.ld 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/ppc.ld 2007-05-11 23:44:50 UTC (rev 1948)
@@ -2,8 +2,8 @@
* Written by Martin Mares <mj at atrey.karlin.mff.cuni.cz>;
*/
OUTPUT_FORMAT("elf32-powerpc", "elf32-powerpc", "elf32-powerpc")
-OUTPUT_ARCH(powerpc)
-SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/usr/alpha-unknown-linux-gnu/lib);
+OUTPUT_ARCH(powerpc:common)
+SEARCH_DIR(/usr/powerpc-linux-gnu/lib); SEARCH_DIR(/usr/local/lib); SEARCH_DIR(/lib); SEARCH_DIR(/usr/lib)
ENTRY(_start)
SECTIONS
{
@@ -16,93 +16,179 @@
.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 :
+ .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 :
{
- *(.text)
+ KEEP (*(.init))
+ } =0
+ .text :
+ {
+ *(.text .stub .text.* .gnu.linkonce.t.*)
+ KEEP (*(.text.*personality*))
/* .gnu.warning sections are handled specially by elf32.em. */
*(.gnu.warning)
- *(.gnu.linkonce.t*)
+ *(.glink)
} =0x47ff041f
- _etext = .;
+ .fini :
+ {
+ KEEP (*(.fini))
+ } =0x47ff041f
+ PROVIDE (__etext = .);
+ PROVIDE (_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) }
+ .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(0x100000) + (. & (0x100000 - 1));
- .data :
+ . = 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 :
{
- *(.data)
- *(.gnu.linkonce.d*)
- CONSTRUCTORS
+ PROVIDE_HIDDEN (__preinit_array_start = .);
+ KEEP (*(.preinit_array))
+ PROVIDE_HIDDEN (__preinit_array_end = .);
}
- .data1 : { *(.data1) }
- .ctors :
+ .init_array :
{
- *(.ctors)
+ PROVIDE_HIDDEN (__init_array_start = .);
+ KEEP (*(SORT(.init_array.*)))
+ KEEP (*(.init_array))
+ PROVIDE_HIDDEN (__init_array_end = .);
}
- .dtors :
+ .fini_array :
{
- *(.dtors)
+ PROVIDE_HIDDEN (__fini_array_start = .);
+ KEEP (*(.fini_array))
+ KEEP (*(SORT(.fini_array.*)))
+ PROVIDE_HIDDEN (__fini_array_end = .);
}
- .plt : { *(.plt) }
- .got : { *(.got.plt) *(.got) }
- .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
+ 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 : { *(.sdata) }
- _edata = .;
- PROVIDE (edata = .);
+ .sdata :
+ {
+ PROVIDE (_SDA_BASE_ = 32768);
+ *(.sdata .sdata.* .gnu.linkonce.s.*)
+ }
+ _edata = .; PROVIDE (edata = .);
__bss_start = .;
- .sbss : { *(.sbss) *(.scommon) }
- .bss :
+ .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 .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);
}
- _end = . ;
- PROVIDE (end = .);
+ . = ALIGN(32 / 8);
+ . = ALIGN(32 / 8);
+ _end = .; PROVIDE (end = .);
+ . = DATA_SEGMENT_END (.);
/* Stabs debugging sections. */
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
@@ -137,4 +223,6 @@
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
/* These must appear regardless of . */
+ /DISCARD/ : { *(.fixup) }
+ /DISCARD/ : { *(.note.GNU-stack) }
}
Modified: trunk/src/host/qemu-neo1973/qemu-binfmt-conf.sh
===================================================================
--- trunk/src/host/qemu-neo1973/qemu-binfmt-conf.sh 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/qemu-binfmt-conf.sh 2007-05-11 23:44:50 UTC (rev 1948)
@@ -1,8 +1,13 @@
#!/bin/sh
-# enable automatic i386/ARM/SPARC/PPC program execution by the kernel
+# enable automatic i386/ARM/M68K/MIPS/SPARC/PPC program execution by the kernel
# load the binfmt_misc module
-/sbin/modprobe binfmt_misc
+if [ ! -d /proc/sys/fs/binfmt_misc ]; then
+ /sbin/modprobe binfmt_misc
+fi
+if [ ! -f /proc/sys/fs/binfmt_misc/register ]; then
+ mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc
+fi
# probe cpu type
cpu=`uname -m`
@@ -10,6 +15,12 @@
i386|i486|i586|i686|i86pc|BePC)
cpu="i386"
;;
+ m68k)
+ cpu="m68k"
+ ;;
+ mips*)
+ cpu="mips"
+ ;;
"Power Macintosh"|ppc|ppc64)
cpu="ppc"
;;
@@ -33,7 +44,12 @@
if [ $cpu != "ppc" ] ; then
echo ':ppc:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x14:\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-ppc:' > /proc/sys/fs/binfmt_misc/register
fi
+if [ $cpu != "m68k" ] ; then
+ echo 'Please check cpu value and header information for m68k!'
+ echo ':m68k:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x08:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-m68k:' > /proc/sys/fs/binfmt_misc/register
+fi
if [ $cpu != "mips" ] ; then
+ # FIXME: We could use the other endianness on a MIPS host.
echo ':mips:M::\x7fELF\x01\x02\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff:/usr/local/bin/qemu-mips:' > /proc/sys/fs/binfmt_misc/register
echo ':mipsel:M::\x7fELF\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x08\x00:\xff\xff\xff\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff\xfe\xff\xff\xff:/usr/local/bin/qemu-mipsel:' > /proc/sys/fs/binfmt_misc/register
fi
Modified: trunk/src/host/qemu-neo1973/qemu-doc.texi
===================================================================
--- trunk/src/host/qemu-neo1973/qemu-doc.texi 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/qemu-doc.texi 2007-05-11 23:44:50 UTC (rev 1948)
@@ -25,7 +25,7 @@
* Installation::
* QEMU PC System emulator::
* QEMU System emulator for non PC targets::
-* QEMU Linux User space emulator::
+* QEMU User space emulator::
* compilation:: Compilation from the sources
* Index::
@end menu
@@ -57,8 +57,8 @@
without rebooting the PC or to debug system code.
@item
-User mode emulation (Linux host only). In this mode, QEMU can launch
-Linux processes compiled for one CPU on another CPU. It can be used to
+User mode emulation. In this mode, QEMU can launch
+processes compiled for one CPU on another CPU. It can be used to
launch the Wine Windows API emulator (@url{http://www.winehq.org}) or
to ease cross-compilation and cross-debugging.
@@ -77,8 +77,10 @@
@item Sun4m (32-bit Sparc processor)
@item Sun4u (64-bit Sparc processor, in progress)
@item Malta board (32-bit MIPS processor)
- at item ARM Integrator/CP (ARM926E or 1026E processor)
+ at item ARM Integrator/CP (ARM926E, 1026E or 946E processor)
@item ARM Versatile baseboard (ARM926E)
+ at item ARM RealView Emulation baseboard (ARM926EJ-S)
+ at item Spitz, Akita, Borzoi and Terrier PDAs (PXA270 processor)
@end itemize
For user emulation, x86, PowerPC, ARM, MIPS, Sparc32/64 and ColdFire(m68k) CPUs are supported.
@@ -247,6 +249,12 @@
the console. Therefore, you can still use QEMU to debug a Linux kernel
with a serial console.
+ at item -no-frame
+
+Do not use decorations for SDL windows and start them using the whole
+available screen space. This makes the using QEMU in a dedicated desktop
+workspace more convenient.
+
@item -vnc display
Normally, QEMU uses SDL to display the VGA output. With this option,
@@ -324,6 +332,10 @@
Load the contents of file as an option ROM. This option is useful to load
things like EtherBoot.
+ at item -name string
+Sets the name of the guest. This name will be display in the SDL window
+caption. The name will also be used for the VNC server.
+
@end table
USB options:
@@ -345,10 +357,12 @@
= 0 is the default). The NIC is currently an NE2000 on the PC
target. Optionally, the MAC address can be changed. If no
@option{-net} option is specified, a single NIC is created.
-Qemu can emulate several different models of network card. Valid values for
- at var{type} are @code{ne2k_pci}, @code{ne2k_isa}, @code{rtl8139},
- at code{smc91c111} and @code{lance}. Not all devices are supported on all
-targets.
+Qemu can emulate several different models of network card.
+Valid values for @var{type} are
+ at code{i82551}, @code{i82557b}, @code{i82559er},
+ at code{ne2k_pci}, @code{ne2k_isa}, @code{pcnet}, @code{rtl8139},
+ at code{smc91c111} and @code{lance}.
+Not all devices are supported on all targets.
@item -net user[,vlan=n][,hostname=name]
Use the user mode network stack which requires no administrator
@@ -358,7 +372,8 @@
@item -net tap[,vlan=n][,fd=h][,ifname=name][,script=file]
Connect the host TAP network interface @var{name} to VLAN @var{n} and
use the network script @var{file} to configure it. The default
-network script is @file{/etc/qemu-ifup}. If @var{name} is not
+network script is @file{/etc/qemu-ifup}. Use @option{script=no} to
+disable script execution. If @var{name} is not
provided, the OS automatically provides one. @option{fd=h} can be
used to specify the handle of an already opened host TAP interface. Example:
@@ -437,14 +452,23 @@
override the default configuration (@option{-net nic -net user}) which
is activated if no @option{-net} options are provided.
- at item -tftp prefix
+ at item -tftp dir
When using the user mode network stack, activate a built-in TFTP
-server. All filenames beginning with @var{prefix} can be downloaded
-from the host to the guest using a TFTP client. The TFTP client on the
-guest must be configured in binary mode (use the command @code{bin} of
-the Unix TFTP client). The host IP address on the guest is as usual
-10.0.2.2.
+server. The files in @var{dir} will be exposed as the root of a TFTP server.
+The TFTP client on the guest must be configured in binary mode (use the command
+ at code{bin} of the Unix TFTP client). The host IP address on the guest is as
+usual 10.0.2.2.
+ at item -bootp file
+When using the user mode network stack, broadcast @var{file} as the BOOTP
+filename. In conjunction with @option{-tftp}, this can be used to network boot
+a guest from a local directory.
+
+Example (using pxelinux):
+ at example
+qemu -hda linux.img -boot n -tftp /path/to/tftp/files -bootp /pxelinux.0
+ at end example
+
@item -smb dir
When using the user mode network stack, activate a built-in SMB
server so that Windows OSes can access to the host files in @file{dir}
@@ -540,7 +564,7 @@
parameters are set according to the emulated ones.
@item /dev/parportN
[Linux only, parallel port only] Use host parallel port
- at var{N}. Currently only SPP parallel port features can be used.
+ at var{N}. Currently SPP and EPP parallel port features can be used.
@item file:filename
Write output to filename. No character can be read.
@item stdio
@@ -576,13 +600,14 @@
@end table
- at item tcp:[host]:port[,server][,nowait]
+ at item tcp:[host]:port[,server][,nowait][,nodelay]
The TCP Net Console has two modes of operation. It can send the serial
I/O to a location or wait for a connection from a location. By default
the TCP Net Console is sent to @var{host} at the @var{port}. If you use
the @var{server} option QEMU will wait for a client socket application
to connect to the port before continuing, unless the @code{nowait}
-option was specified. If @var{host} is omitted, 0.0.0.0 is assumed. Only
+option was specified. The @code{nodelay} option disables the Nagle buffering
+algoritm. If @var{host} is omitted, 0.0.0.0 is assumed. Only
one TCP connection at a time is accepted. You can use @code{telnet} to
connect to the corresponding character device.
@table @code
@@ -594,7 +619,7 @@
-serial tcp:192.168.0.100:4444,server,nowait
@end table
- at item telnet:host:port[,server][,nowait]
+ at item telnet:host:port[,server][,nowait][,nodelay]
The telnet protocol is used instead of raw tcp sockets. The options
work the same as if you had specified @code{-serial tcp}. The
difference is that the port acts like a telnet server or client using
@@ -608,8 +633,20 @@
same as if you had specified @code{-serial tcp} except the unix domain socket
@var{path} is used for connections.
+ at item mon:dev_string
+This is a special option to allow the monitor to be multiplexed onto
+another serial port. The monitor is accessed with key sequence of
+ at key{Control-a} and then pressing @key{c}. See monitor access
+ at ref{pcsys_keys} in the -nographic section for more keys.
+ at var{dev_string} should be any one of the serial devices specified
+above. An example to multiplex the monitor onto a telnet server
+listening on port 4444 would be:
+ at table @code
+ at item -serial mon:telnet::4444,server,nowait
@end table
+ at end table
+
@item -parallel dev
Redirect the virtual parallel port to host device @var{dev} (same
devices as the serial port). On Linux hosts, @file{/dev/parportN} can
@@ -627,10 +664,24 @@
The default device is @code{vc} in graphical mode and @code{stdio} in
non graphical mode.
+ at item -echr numeric_ascii_value
+Change the escape character used for switching to the monitor when using
+monitor and serial sharing. The default is @code{0x01} when using the
+ at code{-nographic} option. @code{0x01} is equal to pressing
+ at code{Control-a}. You can select a different character from the ascii
+control keys where 1 through 26 map to Control-a through Control-z. For
+instance you could use the either of the following to change the escape
+character to Control-t.
+ at table @code
+ at item -echr 0x14
+ at item -echr 20
+ at end table
+
@item -s
Wait gdb connection to port 1234 (@pxref{gdb_usage}).
@item -p port
-Change gdb connection port.
+Change gdb connection port. @var{port} can be either a decimal number
+to specify a TCP port, or a host device (same devices as the serial port).
@item -S
Do not start CPU at startup (you must type 'c' in the monitor).
@item -d
@@ -661,6 +712,11 @@
@item -loadvm file
Start right away with a saved state (@code{loadvm} in monitor)
+
+ at item -semihosting
+Enable "Angel" semihosting interface (ARM target machines only).
+Note that this allows guest direct access to the host filesystem,
+so should only be used with trusted guest OS.
@end table
@c man end
@@ -703,6 +759,8 @@
Exit emulator
@item Ctrl-a s
Save disk data back to file (if -snapshot)
+ at item Ctrl-a t
+toggle console timestamps
@item Ctrl-a b
Send break (magic sysrq in Linux)
@item Ctrl-a c
@@ -734,7 +792,7 @@
@itemize @minus
@item
-Remove or insert removable medias images
+Remove or insert removable media images
(such as CD-ROM or floppies)
@item
@@ -787,10 +845,10 @@
Quit the emulator.
@item eject [-f] device
-Eject a removable media (use -f to force it).
+Eject a removable medium (use -f to force it).
@item change device filename
-Change a removable media.
+Change a removable medium.
@item screendump filename
Save screen into PPM image @var{filename}.
@@ -1085,7 +1143,7 @@
alternate syntax @file{\\.\d:} is supported. @file{/dev/cdrom} is
supported as an alias to the first CDROM drive.
-Currently there is no specific code to handle removable medias, so it
+Currently there is no specific code to handle removable media, so it
is better to use the @code{change} or @code{eject} monitor commands to
change or eject media.
@item Hard disks
@@ -1103,7 +1161,7 @@
@file{/dev/cdrom} is an alias to the first CDROM.
-Currently there is no specific code to handle removable medias, so it
+Currently there is no specific code to handle removable media, so it
is better to use the @code{change} or @code{eject} monitor commands to
change or eject media.
@@ -1605,6 +1663,15 @@
Set the initial TCX graphic mode. The default is 1024x768.
+ at item -prom-env string
+
+Set OpenBIOS variables in NVRAM, for example:
+
+ at example
+qemu-system-sparc -prom-env 'auto-boot?=false' \
+ -prom-env 'boot-device=sd(0,2,0):d' -prom-env 'boot-args=linux single'
+ at end example
+
@end table
@c man end
@@ -1655,7 +1722,7 @@
@itemize @minus
@item
-ARM926E or ARM1026E CPU
+ARM926E, ARM1026E or ARM946E CPU
@item
Two PL011 UARTs
@item
@@ -1664,6 +1731,8 @@
PL110 LCD controller
@item
PL050 KMI with PS/2 keyboard and mouse.
+ at item
+PL181 MultiMedia Card Interface with SD card.
@end itemize
The ARM Versatile baseboard is emulated with the following devices:
@@ -1691,15 +1760,93 @@
PCI OHCI USB controller.
@item
LSI53C895A PCI SCSI Host Bus Adapter with hard disk and CD-ROM devices.
+ at item
+PL181 MultiMedia Card Interface with SD card.
@end itemize
+The ARM RealView Emulation baseboard is emulated with the following devices:
+
+ at itemize @minus
+ at item
+ARM926E CPU
+ at item
+ARM AMBA Generic/Distributed Interrupt Controller
+ at item
+Four PL011 UARTs
+ at item
+SMC 91c111 Ethernet adapter
+ at item
+PL110 LCD controller
+ at item
+PL050 KMI with PS/2 keyboard and mouse
+ at item
+PCI host bridge
+ at item
+PCI OHCI USB controller
+ at item
+LSI53C895A PCI SCSI Host Bus Adapter with hard disk and CD-ROM devices
+ at item
+PL181 MultiMedia Card Interface with SD card.
+ at end itemize
+
+The XScale-based clamshell PDA models ("Spitz", "Akita", "Borzoi"
+and "Terrier") emulation includes the following peripherals:
+
+ at itemize @minus
+ at item
+Intel PXA270 System-on-chip (ARM V5TE core)
+ at item
+NAND Flash memory
+ at item
+IBM/Hitachi DSCM microdrive in a PXA PCMCIA slot - not in "Akita"
+ at item
+On-chip OHCI USB controller
+ at item
+On-chip LCD controller
+ at item
+On-chip Real Time Clock
+ at item
+TI ADS7846 touchscreen controller on SSP bus
+ at item
+Maxim MAX1111 analog-digital converter on I at math{^2}C bus
+ at item
+GPIO-connected keyboard controller and LEDs
+ at item
+Secure Digital card connected to PXA MMC/SD host
+ at item
+Three on-chip UARTs
+ at item
+WM8750 audio CODEC on I at math{^2}C and I at math{^2}S busses
+ at end itemize
+
A Linux 2.6 test image is available on the QEMU web site. More
information is available in the QEMU mailing-list archive.
- at node QEMU Linux User space emulator
- at chapter QEMU Linux User space emulator
+ at node QEMU User space emulator
+ at chapter QEMU User space emulator
@menu
+* Supported Operating Systems ::
+* Linux User space emulator::
+* Mac OS X/Darwin User space emulator ::
+ at end menu
+
+ at node Supported Operating Systems
+ at section Supported Operating Systems
+
+The following OS are supported in user space emulation:
+
+ at itemize @minus
+ at item
+Linux (refered as qemu-linux-user)
+ at item
+Mac OS X/Darwin (refered as qemu-darwin-user)
+ at end itemize
+
+ at node Linux User space emulator
+ at section Linux User space emulator
+
+ at menu
* Quick Start::
* Wine launch::
* Command line options::
@@ -1707,7 +1854,7 @@
@end menu
@node Quick Start
- at section Quick Start
+ at subsection Quick Start
In order to launch a Linux process, QEMU needs the process executable
itself and all the target (x86) dynamic libraries used by it.
@@ -1724,7 +1871,8 @@
@code{-L /} tells that the x86 dynamic linker must be searched with a
@file{/} prefix.
- at item Since QEMU is also a linux process, you can launch qemu with qemu (NOTE: you can only do that if you compiled QEMU from the sources):
+ at item Since QEMU is also a linux process, you can launch qemu with
+qemu (NOTE: you can only do that if you compiled QEMU from the sources):
@example
qemu-i386 -L / qemu-i386 -L / /bin/ls
@@ -1757,7 +1905,7 @@
@end itemize
@node Wine launch
- at section Wine launch
+ at subsection Wine launch
@itemize
@@ -1786,7 +1934,7 @@
@end itemize
@node Command line options
- at section Command line options
+ at subsection Command line options
@example
usage: qemu-i386 [-h] [-d] [-L path] [-s size] program [arguments...]
@@ -1811,7 +1959,7 @@
@end table
@node Other binaries
- at section Other binaries
+ at subsection Other binaries
@command{qemu-arm} is also capable of running ARM "Angel" semihosted ELF
binaries (as implemented by the arm-elf and arm-eabi Newlib/GDB
@@ -1823,6 +1971,91 @@
The binary format is detected automatically.
+ at node Mac OS X/Darwin User space emulator
+ at section Mac OS X/Darwin User space emulator
+
+ at menu
+* Mac OS X/Darwin Status::
+* Mac OS X/Darwin Quick Start::
+* Mac OS X/Darwin Command line options::
+ at end menu
+
+ at node Mac OS X/Darwin Status
+ at subsection Mac OS X/Darwin Status
+
+ at itemize @minus
+ at item
+target x86 on x86: Most apps (Cocoa and Carbon too) works. [1]
+ at item
+target PowerPC on x86: Not working as the ppc commpage can't be mapped (yet!)
+ at item
+target PowerPC on PowerPC: Most apps (Cocoa and Carbon too) works. [1]
+ at item
+target x86 on PowerPC: most utilities work. Cocoa and Carbon apps are not yet supported.
+ at end itemize
+
+[1] If you're host commpage can be executed by qemu.
+
+ at node Mac OS X/Darwin Quick Start
+ at subsection Quick Start
+
+In order to launch a Mac OS X/Darwin process, QEMU needs the process executable
+itself and all the target dynamic libraries used by it. If you don't have the FAT
+libraries (you're running Mac OS X/ppc) you'll need to obtain it from a Mac OS X
+CD or compile them by hand.
+
+ at itemize
+
+ at item On x86, you can just try to launch any process by using the native
+libraries:
+
+ at example
+qemu-i386 /bin/ls
+ at end example
+
+or to run the ppc version of the executable:
+
+ at example
+qemu-ppc /bin/ls
+ at end example
+
+ at item On ppc, you'll have to tell qemu where your x86 libraries (and dynamic linker)
+are installed:
+
+ at example
+qemu-i386 -L /opt/x86_root/ /bin/ls
+ at end example
+
+ at code{-L /opt/x86_root/} tells that the dynamic linker (dyld) path is in
+ at file{/opt/x86_root/usr/bin/dyld}.
+
+ at end itemize
+
+ at node Mac OS X/Darwin Command line options
+ at subsection Command line options
+
+ at example
+usage: qemu-i386 [-h] [-d] [-L path] [-s size] program [arguments...]
+ at end example
+
+ at table @option
+ at item -h
+Print the help
+ at item -L path
+Set the library root path (default=/)
+ at item -s size
+Set the stack size in bytes (default=524288)
+ at end table
+
+Debug options:
+
+ at table @option
+ at item -d
+Activate log (logfile=/tmp/qemu.log)
+ at item -p pagesize
+Act as if the host page size was 'pagesize' bytes
+ at end table
+
@node compilation
@chapter Compilation from the sources
@@ -1857,40 +2090,16 @@
@end example
to install QEMU in @file{/usr/local}.
- at subsection Tested tool versions
+ at subsection GCC version
In order to compile QEMU successfully, it is very important that you
-have the right tools. The most important one is gcc. I cannot guaranty
-that QEMU works if you do not use a tested gcc version. Look at
-'configure' and 'Makefile' if you want to make a different gcc
-version work.
+have the right tools. The most important one is gcc. On most hosts and
+in particular on x86 ones, @emph{gcc 4.x is not supported}. If your
+Linux distribution includes a gcc 4.x compiler, you can usually
+install an older version (it is invoked by @code{gcc32} or
+ at code{gcc34}). The QEMU configure script automatically probes for
+these older versions so that usally you don't have to do anything.
- at example
-host gcc binutils glibc linux distribution
-----------------------------------------------------------------------
-x86 3.2 2.13.2 2.1.3 2.4.18
- 2.96 2.11.93.0.2 2.2.5 2.4.18 Red Hat 7.3
- 3.2.2 2.13.90.0.18 2.3.2 2.4.20 Red Hat 9
-
-PowerPC 3.3 [4] 2.13.90.0.18 2.3.1 2.4.20briq
- 3.2
-
-Alpha 3.3 [1] 2.14.90.0.4 2.2.5 2.2.20 [2] Debian 3.0
-
-Sparc32 2.95.4 2.12.90.0.1 2.2.5 2.4.18 Debian 3.0
-
-ARM 2.95.4 2.12.90.0.1 2.2.5 2.4.9 [3] Debian 3.0
-
-[1] On Alpha, QEMU needs the gcc 'visibility' attribute only available
- for gcc version >= 3.3.
-[2] Linux >= 2.4.20 is necessary for precise exception support
- (untested).
-[3] 2.4.9-ac10-rmk2-np1-cerf2
-
-[4] gcc 2.95.x generates invalid code when using too many register
-variables. You must use gcc 3.x on PowerPC.
- at end example
-
@node Windows
@section Windows
Modified: trunk/src/host/qemu-neo1973/qemu-img.c
===================================================================
--- trunk/src/host/qemu-neo1973/qemu-img.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/qemu-img.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -1,7 +1,7 @@
/*
* QEMU disk image utility
*
- * Copyright (c) 2003-2006 Fabrice Bellard
+ * Copyright (c) 2003-2007 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
@@ -93,7 +93,7 @@
void help(void)
{
- printf("qemu-img version " QEMU_VERSION ", Copyright (c) 2004-2006 Fabrice Bellard\n"
+ printf("qemu-img version " QEMU_VERSION ", Copyright (c) 2004-2007 Fabrice Bellard\n"
"usage: qemu-img command [command options]\n"
"QEMU disk image utility\n"
"\n"
@@ -457,7 +457,7 @@
drv = bdrv_find_format(out_fmt);
if (!drv)
- error("Unknown file format '%s'", fmt);
+ error("Unknown file format '%s'", out_fmt);
if (compress && drv != &bdrv_qcow && drv != &bdrv_qcow2)
error("Compression not supported for this file format");
if (encrypt && drv != &bdrv_qcow && drv != &bdrv_qcow2)
Modified: trunk/src/host/qemu-neo1973/qemu-tech.texi
===================================================================
--- trunk/src/host/qemu-neo1973/qemu-tech.texi 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/qemu-tech.texi 2007-05-11 23:44:50 UTC (rev 1948)
@@ -169,11 +169,11 @@
@itemize
- at item Somewhat complete SPARC V8 emulation, including privileged
+ at item Full SPARC V8 emulation, including privileged
instructions, FPU and MMU. SPARC V9 emulation includes most privileged
-instructions, FPU and I/D MMU, but misses VIS instructions.
+instructions, FPU and I/D MMU, but misses most VIS instructions.
- at item Can run some 32-bit SPARC Linux binaries.
+ at item Can run most 32-bit SPARC Linux binaries and some handcrafted 64-bit SPARC Linux binaries.
@end itemize
@@ -181,9 +181,6 @@
@itemize
- at item Tagged add/subtract instructions are not supported, but they are
-probably not used.
-
@item IPC syscalls are missing.
@item 128-bit floating point operations are not supported, though none of the
Modified: trunk/src/host/qemu-neo1973/sdl.c
===================================================================
--- trunk/src/host/qemu-neo1973/sdl.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/sdl.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -34,6 +34,7 @@
static int last_vm_running;
static int gui_saved_grab;
static int gui_fullscreen;
+static int gui_noframe;
static int gui_key_modifier_pressed;
static int gui_keysym;
static int gui_fullscreen_initial_grab;
@@ -43,6 +44,9 @@
static SDL_Cursor *sdl_cursor_normal;
static SDL_Cursor *sdl_cursor_hidden;
static int absolute_enabled = 0;
+static int guest_cursor = 0;
+static int guest_x, guest_y;
+static SDL_Cursor *guest_sprite = 0;
static void sdl_update(DisplayState *ds, int x, int y, int w, int h)
{
@@ -59,6 +63,8 @@
flags = SDL_HWSURFACE|SDL_ASYNCBLIT|SDL_HWACCEL;
if (gui_fullscreen)
flags |= SDL_FULLSCREEN;
+ if (gui_noframe)
+ flags |= SDL_NOFRAME;
width = w;
height = h;
@@ -122,88 +128,6 @@
#else
-static const uint8_t x_keycode_to_pc_keycode[115] = {
- 0xc7, /* 97 Home */
- 0xc8, /* 98 Up */
- 0xc9, /* 99 PgUp */
- 0xcb, /* 100 Left */
- 0x4c, /* 101 KP-5 */
- 0xcd, /* 102 Right */
- 0xcf, /* 103 End */
- 0xd0, /* 104 Down */
- 0xd1, /* 105 PgDn */
- 0xd2, /* 106 Ins */
- 0xd3, /* 107 Del */
- 0x9c, /* 108 Enter */
- 0x9d, /* 109 Ctrl-R */
- 0x0, /* 110 Pause */
- 0xb7, /* 111 Print */
- 0xb5, /* 112 Divide */
- 0xb8, /* 113 Alt-R */
- 0xc6, /* 114 Break */
- 0x0, /* 115 */
- 0x0, /* 116 */
- 0x0, /* 117 */
- 0x0, /* 118 */
- 0x0, /* 119 */
- 0x0, /* 120 */
- 0x0, /* 121 */
- 0x0, /* 122 */
- 0x0, /* 123 */
- 0x0, /* 124 */
- 0x0, /* 125 */
- 0x0, /* 126 */
- 0x0, /* 127 */
- 0x0, /* 128 */
- 0x79, /* 129 Henkan */
- 0x0, /* 130 */
- 0x7b, /* 131 Muhenkan */
- 0x0, /* 132 */
- 0x7d, /* 133 Yen */
- 0x0, /* 134 */
- 0x0, /* 135 */
- 0x47, /* 136 KP_7 */
- 0x48, /* 137 KP_8 */
- 0x49, /* 138 KP_9 */
- 0x4b, /* 139 KP_4 */
- 0x4c, /* 140 KP_5 */
- 0x4d, /* 141 KP_6 */
- 0x4f, /* 142 KP_1 */
- 0x50, /* 143 KP_2 */
- 0x51, /* 144 KP_3 */
- 0x52, /* 145 KP_0 */
- 0x53, /* 146 KP_. */
- 0x47, /* 147 KP_HOME */
- 0x48, /* 148 KP_UP */
- 0x49, /* 149 KP_PgUp */
- 0x4b, /* 150 KP_Left */
- 0x4c, /* 151 KP_ */
- 0x4d, /* 152 KP_Right */
- 0x4f, /* 153 KP_End */
- 0x50, /* 154 KP_Down */
- 0x51, /* 155 KP_PgDn */
- 0x52, /* 156 KP_Ins */
- 0x53, /* 157 KP_Del */
- 0x0, /* 158 */
- 0x0, /* 159 */
- 0x0, /* 160 */
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, /* 170 */
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, /* 180 */
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, /* 190 */
- 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, /* 200 */
- 0x0, /* 201 */
- 0x0, /* 202 */
- 0x0, /* 203 */
- 0x0, /* 204 */
- 0x0, /* 205 */
- 0x0, /* 206 */
- 0x0, /* 207 */
- 0x70, /* 208 Hiragana_Katakana */
- 0x0, /* 209 */
- 0x0, /* 210 */
- 0x73, /* 211 backslash */
-};
-
static uint8_t sdl_keyevent_to_keycode(const SDL_KeyboardEvent *ev)
{
int keycode;
@@ -216,7 +140,7 @@
keycode -= 8; /* just an offset */
} else if (keycode < 212) {
/* use conversion table */
- keycode = x_keycode_to_pc_keycode[keycode - 97];
+ keycode = _translate_keycode(keycode - 97);
} else {
keycode = 0;
}
@@ -295,13 +219,18 @@
static void sdl_update_caption(void)
{
char buf[1024];
- strcpy(buf, "QEMU");
- if (!vm_running) {
- strcat(buf, " [Stopped]");
- }
- if (gui_grab) {
- strcat(buf, " - Press Ctrl-Alt to exit grab");
- }
+ const char *status = "";
+
+ if (!vm_running)
+ status = " [Stopped]";
+ else if (gui_grab)
+ status = " - Press Ctrl-Alt to exit grab";
+
+ if (qemu_name)
+ snprintf(buf, sizeof(buf), "QEMU (%s)%s", qemu_name, status);
+ else
+ snprintf(buf, sizeof(buf), "QEMU%s", status);
+
SDL_WM_SetCaption(buf, "QEMU");
}
@@ -325,13 +254,21 @@
if (!kbd_mouse_is_absolute()) {
SDL_ShowCursor(1);
- SDL_SetCursor(sdl_cursor_normal);
+ if (guest_cursor &&
+ (gui_grab || kbd_mouse_is_absolute() || absolute_enabled))
+ SDL_SetCursor(guest_sprite);
+ else
+ SDL_SetCursor(sdl_cursor_normal);
}
}
static void sdl_grab_start(void)
{
- sdl_hide_cursor();
+ if (guest_cursor) {
+ SDL_SetCursor(guest_sprite);
+ SDL_WarpMouse(guest_x, guest_y);
+ } else
+ sdl_hide_cursor();
SDL_WM_GrabInput(SDL_GRAB_ON);
/* dummy read to avoid moving the mouse */
SDL_GetRelativeMouseState(NULL, NULL);
@@ -342,8 +279,8 @@
static void sdl_grab_end(void)
{
SDL_WM_GrabInput(SDL_GRAB_OFF);
+ gui_grab = 0;
sdl_show_cursor();
- gui_grab = 0;
sdl_update_caption();
}
@@ -374,6 +311,12 @@
} else if (absolute_enabled) {
sdl_show_cursor();
absolute_enabled = 0;
+ } else if (guest_cursor) {
+ SDL_GetMouseState(&dx, &dy);
+ dx -= guest_x;
+ dy -= guest_y;
+ guest_x += dx;
+ guest_y += dy;
}
kbd_mouse_event(dx, dy, dz, buttons);
@@ -552,12 +495,81 @@
}
}
+static void sdl_fill(DisplayState *ds, int x, int y, int w, int h, uint32_t c)
+{
+ SDL_Rect dst = { x, y, w, h };
+ SDL_FillRect(screen, &dst, c);
+}
+
+static void sdl_mouse_warp(int x, int y, int on)
+{
+ if (on) {
+ if (!guest_cursor)
+ sdl_show_cursor();
+ if (gui_grab || kbd_mouse_is_absolute() || absolute_enabled) {
+ SDL_SetCursor(guest_sprite);
+ SDL_WarpMouse(x, y);
+ }
+ } else if (gui_grab)
+ sdl_hide_cursor();
+ guest_cursor = on;
+ guest_x = x, guest_y = y;
+}
+
+static void sdl_mouse_define(int width, int height, int bpp,
+ int hot_x, int hot_y,
+ uint8_t *image, uint8_t *mask)
+{
+ uint8_t sprite[256], *line;
+ int x, y, dst, bypl, src = 0;
+ if (guest_sprite)
+ SDL_FreeCursor(guest_sprite);
+
+ memset(sprite, 0, 256);
+ bypl = ((width * bpp + 31) >> 5) << 2;
+ for (y = 0, dst = 0; y < height; y ++, image += bypl) {
+ line = image;
+ for (x = 0; x < width; x ++, dst ++) {
+ switch (bpp) {
+ case 24:
+ src = *(line ++); src |= *(line ++); src |= *(line ++);
+ break;
+ case 16:
+ case 15:
+ src = *(line ++); src |= *(line ++);
+ break;
+ case 8:
+ src = *(line ++);
+ break;
+ case 4:
+ src = 0xf & (line[x >> 1] >> ((x & 1)) << 2);
+ break;
+ case 2:
+ src = 3 & (line[x >> 2] >> ((x & 3)) << 1);
+ break;
+ case 1:
+ src = 1 & (line[x >> 3] >> (x & 7));
+ break;
+ }
+ if (!src)
+ sprite[dst >> 3] |= (1 << (~dst & 7)) & mask[dst >> 3];
+ }
+ }
+ guest_sprite = SDL_CreateCursor(sprite, mask, width, height, hot_x, hot_y);
+
+ if (guest_cursor &&
+ (gui_grab || kbd_mouse_is_absolute() || absolute_enabled))
+ SDL_SetCursor(guest_sprite);
+}
+
static void sdl_cleanup(void)
{
+ if (guest_sprite)
+ SDL_FreeCursor(guest_sprite);
SDL_Quit();
}
-void sdl_display_init(DisplayState *ds, int full_screen)
+void sdl_display_init(DisplayState *ds, int full_screen, int no_frame)
{
int flags;
uint8_t data = 0;
@@ -573,6 +585,9 @@
exit(1);
}
+ if (no_frame)
+ gui_noframe = 1;
+
flags = SDL_INIT_VIDEO | SDL_INIT_NOPARACHUTE;
if (SDL_Init (flags)) {
fprintf(stderr, "Could not initialize SDL - exiting\n");
@@ -587,6 +602,9 @@
ds->dpy_update = sdl_update;
ds->dpy_resize = sdl_resize;
ds->dpy_refresh = sdl_refresh;
+ ds->dpy_fill = sdl_fill;
+ ds->mouse_set = sdl_mouse_warp;
+ ds->cursor_define = sdl_mouse_define;
sdl_resize(ds, 640, 400);
sdl_update_caption();
Modified: trunk/src/host/qemu-neo1973/slirp/bootp.c
===================================================================
--- trunk/src/host/qemu-neo1973/slirp/bootp.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/slirp/bootp.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -38,6 +38,8 @@
BOOTPClient bootp_clients[NB_ADDR];
+const char *bootp_filename;
+
static const uint8_t rfc1533_cookie[] = { RFC1533_COOKIE };
#ifdef DEBUG
@@ -168,6 +170,10 @@
goto new_addr;
}
}
+
+ if (bootp_filename)
+ snprintf(rbp->bp_file, sizeof(rbp->bp_file), "%s", bootp_filename);
+
dprintf("offered addr=%08x\n", ntohl(daddr.sin_addr.s_addr));
saddr.sin_addr.s_addr = htonl(ntohl(special_addr.s_addr) | CTL_ALIAS);
Modified: trunk/src/host/qemu-neo1973/slirp/tftp.c
===================================================================
--- trunk/src/host/qemu-neo1973/slirp/tftp.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/slirp/tftp.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -102,9 +102,16 @@
{
int fd;
int bytes_read = 0;
+ char buffer[1024];
+ int n;
- fd = open(spt->filename, O_RDONLY | O_BINARY);
+ n = snprintf(buffer, sizeof(buffer), "%s/%s",
+ tftp_prefix, spt->filename);
+ if (n >= sizeof(buffer))
+ return -1;
+ fd = open(buffer, O_RDONLY | O_BINARY);
+
if (fd < 0) {
return -1;
}
@@ -120,6 +127,45 @@
return bytes_read;
}
+static int tftp_send_oack(struct tftp_session *spt,
+ const char *key, uint32_t value,
+ struct tftp_t *recv_tp)
+{
+ struct sockaddr_in saddr, daddr;
+ struct mbuf *m;
+ struct tftp_t *tp;
+ int n = 0;
+
+ m = m_get();
+
+ if (!m)
+ return -1;
+
+ memset(m->m_data, 0, m->m_size);
+
+ m->m_data += if_maxlinkhdr;
+ tp = (void *)m->m_data;
+ m->m_data += sizeof(struct udpiphdr);
+
+ tp->tp_op = htons(TFTP_OACK);
+ n += sprintf(tp->x.tp_buf + n, "%s", key) + 1;
+ n += sprintf(tp->x.tp_buf + n, "%u", value) + 1;
+
+ saddr.sin_addr = recv_tp->ip.ip_dst;
+ saddr.sin_port = recv_tp->udp.uh_dport;
+
+ daddr.sin_addr = spt->client_ip;
+ daddr.sin_port = spt->client_port;
+
+ m->m_len = sizeof(struct tftp_t) - 514 + n -
+ sizeof(struct ip) - sizeof(struct udphdr);
+ udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY);
+
+ return 0;
+}
+
+
+
static int tftp_send_error(struct tftp_session *spt,
u_int16_t errorcode, const char *msg,
struct tftp_t *recv_tp)
@@ -273,6 +319,8 @@
return;
}
+ k += 6; /* skipping octet */
+
/* do sanity checks on the filename */
if ((spt->filename[0] != '/')
@@ -284,8 +332,7 @@
/* only allow exported prefixes */
- if (!tftp_prefix
- || (strncmp(spt->filename, tftp_prefix, strlen(tftp_prefix)) != 0)) {
+ if (!tftp_prefix) {
tftp_send_error(spt, 2, "Access violation", tp);
return;
}
@@ -297,6 +344,48 @@
return;
}
+ if (src[n - 1] != 0) {
+ tftp_send_error(spt, 2, "Access violation", tp);
+ return;
+ }
+
+ while (k < n) {
+ const char *key, *value;
+
+ key = src + k;
+ k += strlen(key) + 1;
+
+ if (k >= n) {
+ tftp_send_error(spt, 2, "Access violation", tp);
+ return;
+ }
+
+ value = src + k;
+ k += strlen(value) + 1;
+
+ if (strcmp(key, "tsize") == 0) {
+ int tsize = atoi(value);
+ struct stat stat_p;
+
+ if (tsize == 0 && tftp_prefix) {
+ char buffer[1024];
+ int len;
+
+ len = snprintf(buffer, sizeof(buffer), "%s/%s",
+ tftp_prefix, spt->filename);
+
+ if (stat(buffer, &stat_p) == 0)
+ tsize = stat_p.st_size;
+ else {
+ tftp_send_error(spt, 1, "File not found", tp);
+ return;
+ }
+ }
+
+ tftp_send_oack(spt, "tsize", tsize, tp);
+ }
+ }
+
tftp_send_data(spt, 1, tp);
}
Modified: trunk/src/host/qemu-neo1973/slirp/tftp.h
===================================================================
--- trunk/src/host/qemu-neo1973/slirp/tftp.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/slirp/tftp.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -9,6 +9,7 @@
#define TFTP_DATA 3
#define TFTP_ACK 4
#define TFTP_ERROR 5
+#define TFTP_OACK 6
#define TFTP_FILENAME_MAX 512
Modified: trunk/src/host/qemu-neo1973/slirp/udp.c
===================================================================
--- trunk/src/host/qemu-neo1973/slirp/udp.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/slirp/udp.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -205,8 +205,6 @@
/* udp_last_so = so; */
so->so_laddr = ip->ip_src;
so->so_lport = uh->uh_sport;
- so->so_faddr = ip->ip_dst; /* XXX */
- so->so_fport = uh->uh_dport; /* XXX */
if ((so->so_iptos = udp_tos(so)) == 0)
so->so_iptos = ip->ip_tos;
@@ -217,6 +215,9 @@
*/
}
+ so->so_faddr = ip->ip_dst; /* XXX */
+ so->so_fport = uh->uh_dport; /* XXX */
+
iphlen += sizeof(struct udphdr);
m->m_len -= iphlen;
m->m_data += iphlen;
Modified: trunk/src/host/qemu-neo1973/softmmu_header.h
===================================================================
--- trunk/src/host/qemu-neo1973/softmmu_header.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/softmmu_header.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -63,6 +63,8 @@
#define CPU_MEM_INDEX ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR)
#elif defined (TARGET_SH4)
#define CPU_MEM_INDEX ((env->sr & SR_MD) == 0)
+#elif defined (TARGET_ALPHA)
+#define CPU_MEM_INDEX ((env->ps >> 3) & 3)
#else
#error unsupported CPU
#endif
@@ -82,6 +84,8 @@
#define CPU_MEM_INDEX ((env->uncached_cpsr & CPSR_M) == ARM_CPU_MODE_USR)
#elif defined (TARGET_SH4)
#define CPU_MEM_INDEX ((env->sr & SR_MD) == 0)
+#elif defined (TARGET_ALPHA)
+#define CPU_MEM_INDEX ((env->ps >> 3) & 3)
#else
#error unsupported CPU
#endif
Modified: trunk/src/host/qemu-neo1973/sparc.ld
===================================================================
--- trunk/src/host/qemu-neo1973/sparc.ld 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/sparc.ld 2007-05-11 23:44:50 UTC (rev 1948)
@@ -64,6 +64,8 @@
CONSTRUCTORS
}
.data1 : { *(.data1) }
+ .tdata : { *(.tdata) }
+ .tbss : { *(.tbss) }
.ctors :
{
*(.ctors)
@@ -125,4 +127,5 @@
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
/* These must appear regardless of . */
+ /DISCARD/ : { *(.note.GNU-stack) *(.note.ABI-tag) }
}
Added: trunk/src/host/qemu-neo1973/target-alpha/cpu.h
===================================================================
--- trunk/src/host/qemu-neo1973/target-alpha/cpu.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/target-alpha/cpu.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,398 @@
+/*
+ * Alpha emulation cpu definitions for qemu.
+ *
+ * Copyright (c) 2007 Jocelyn Mayer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if !defined (__CPU_ALPHA_H__)
+#define __CPU_ALPHA_H__
+
+#include "config.h"
+
+#define TARGET_LONG_BITS 64
+
+#include "cpu-defs.h"
+
+
+#include <setjmp.h>
+
+#include "softfloat.h"
+
+/* XXX: put this in a common place */
+#define likely(x) __builtin_expect(!!(x), 1)
+#define unlikely(x) __builtin_expect(!!(x), 0)
+
+#define TARGET_HAS_ICE 1
+
+#define ELF_MACHINE EM_ALPHA
+
+#define ICACHE_LINE_SIZE 32
+#define DCACHE_LINE_SIZE 32
+
+#define TARGET_PAGE_BITS 12
+
+#define VA_BITS 43
+
+/* Alpha major type */
+enum {
+ ALPHA_EV3 = 1,
+ ALPHA_EV4 = 2,
+ ALPHA_SIM = 3,
+ ALPHA_LCA = 4,
+ ALPHA_EV5 = 5, /* 21164 */
+ ALPHA_EV45 = 6, /* 21064A */
+ ALPHA_EV56 = 7, /* 21164A */
+};
+
+/* EV4 minor type */
+enum {
+ ALPHA_EV4_2 = 0,
+ ALPHA_EV4_3 = 1,
+};
+
+/* LCA minor type */
+enum {
+ ALPHA_LCA_1 = 1, /* 21066 */
+ ALPHA_LCA_2 = 2, /* 20166 */
+ ALPHA_LCA_3 = 3, /* 21068 */
+ ALPHA_LCA_4 = 4, /* 21068 */
+ ALPHA_LCA_5 = 5, /* 21066A */
+ ALPHA_LCA_6 = 6, /* 21068A */
+};
+
+/* EV5 minor type */
+enum {
+ ALPHA_EV5_1 = 1, /* Rev BA, CA */
+ ALPHA_EV5_2 = 2, /* Rev DA, EA */
+ ALPHA_EV5_3 = 3, /* Pass 3 */
+ ALPHA_EV5_4 = 4, /* Pass 3.2 */
+ ALPHA_EV5_5 = 5, /* Pass 4 */
+};
+
+/* EV45 minor type */
+enum {
+ ALPHA_EV45_1 = 1, /* Pass 1 */
+ ALPHA_EV45_2 = 2, /* Pass 1.1 */
+ ALPHA_EV45_3 = 3, /* Pass 2 */
+};
+
+/* EV56 minor type */
+enum {
+ ALPHA_EV56_1 = 1, /* Pass 1 */
+ ALPHA_EV56_2 = 2, /* Pass 2 */
+};
+
+enum {
+ IMPLVER_2106x = 0, /* EV4, EV45 & LCA45 */
+ IMPLVER_21164 = 1, /* EV5, EV56 & PCA45 */
+ IMPLVER_21264 = 2, /* EV6, EV67 & EV68x */
+ IMPLVER_21364 = 3, /* EV7 & EV79 */
+};
+
+enum {
+ AMASK_BWX = 0x00000001,
+ AMASK_FIX = 0x00000002,
+ AMASK_CIX = 0x00000004,
+ AMASK_MVI = 0x00000100,
+ AMASK_TRAP = 0x00000200,
+ AMASK_PREFETCH = 0x00001000,
+};
+
+enum {
+ VAX_ROUND_NORMAL = 0,
+ VAX_ROUND_CHOPPED,
+};
+
+enum {
+ IEEE_ROUND_NORMAL = 0,
+ IEEE_ROUND_DYNAMIC,
+ IEEE_ROUND_PLUS,
+ IEEE_ROUND_MINUS,
+ IEEE_ROUND_CHOPPED,
+};
+
+/* IEEE floating-point operations encoding */
+/* Trap mode */
+enum {
+ FP_TRAP_I = 0x0,
+ FP_TRAP_U = 0x1,
+ FP_TRAP_S = 0x4,
+ FP_TRAP_SU = 0x5,
+ FP_TRAP_SUI = 0x7,
+};
+
+/* Rounding mode */
+enum {
+ FP_ROUND_CHOPPED = 0x0,
+ FP_ROUND_MINUS = 0x1,
+ FP_ROUND_NORMAL = 0x2,
+ FP_ROUND_DYNAMIC = 0x3,
+};
+
+/* Internal processor registers */
+/* XXX: TOFIX: most of those registers are implementation dependant */
+enum {
+ /* Ebox IPRs */
+ IPR_CC = 0xC0,
+ IPR_CC_CTL = 0xC1,
+ IPR_VA = 0xC2,
+ IPR_VA_CTL = 0xC4,
+ IPR_VA_FORM = 0xC3,
+ /* Ibox IPRs */
+ IPR_ITB_TAG = 0x00,
+ IPR_ITB_PTE = 0x01,
+ IPT_ITB_IAP = 0x02,
+ IPT_ITB_IA = 0x03,
+ IPT_ITB_IS = 0x04,
+ IPR_PMPC = 0x05,
+ IPR_EXC_ADDR = 0x06,
+ IPR_IVA_FORM = 0x07,
+ IPR_CM = 0x09,
+ IPR_IER = 0x0A,
+ IPR_SIRR = 0x0C,
+ IPR_ISUM = 0x0D,
+ IPR_HW_INT_CLR = 0x0E,
+ IPR_EXC_SUM = 0x0F,
+ IPR_PAL_BASE = 0x10,
+ IPR_I_CTL = 0x11,
+ IPR_I_STAT = 0x16,
+ IPR_IC_FLUSH = 0x13,
+ IPR_IC_FLUSH_ASM = 0x12,
+ IPR_CLR_MAP = 0x15,
+ IPR_SLEEP = 0x17,
+ IPR_PCTX = 0x40,
+ IPR_PCTR_CTL = 0x14,
+ /* Mbox IPRs */
+ IPR_DTB_TAG0 = 0x20,
+ IPR_DTB_TAG1 = 0xA0,
+ IPR_DTB_PTE0 = 0x21,
+ IPR_DTB_PTE1 = 0xA1,
+ IPR_DTB_ALTMODE = 0xA6,
+ IPR_DTB_IAP = 0xA2,
+ IPR_DTB_IA = 0xA3,
+ IPR_DTB_IS0 = 0x24,
+ IPR_DTB_IS1 = 0xA4,
+ IPR_DTB_ASN0 = 0x25,
+ IPR_DTB_ASN1 = 0xA5,
+ IPR_MM_STAT = 0x27,
+ IPR_M_CTL = 0x28,
+ IPR_DC_CTL = 0x29,
+ IPR_DC_STAT = 0x2A,
+ /* Cbox IPRs */
+ IPR_C_DATA = 0x2B,
+ IPR_C_SHIFT = 0x2C,
+
+ IPR_ASN,
+ IPR_ASTEN,
+ IPR_ASTSR,
+ IPR_DATFX,
+ IPR_ESP,
+ IPR_FEN,
+ IPR_IPIR,
+ IPR_IPL,
+ IPR_KSP,
+ IPR_MCES,
+ IPR_PERFMON,
+ IPR_PCBB,
+ IPR_PRBR,
+ IPR_PTBR,
+ IPR_SCBB,
+ IPR_SISR,
+ IPR_SSP,
+ IPR_SYSPTBR,
+ IPR_TBCHK,
+ IPR_TBIA,
+ IPR_TBIAP,
+ IPR_TBIS,
+ IPR_TBISD,
+ IPR_TBISI,
+ IPR_USP,
+ IPR_VIRBND,
+ IPR_VPTB,
+ IPR_WHAMI,
+ IPR_ALT_MODE,
+ IPR_LAST,
+};
+
+typedef struct CPUAlphaState CPUAlphaState;
+
+typedef struct pal_handler_t pal_handler_t;
+struct pal_handler_t {
+ /* Reset */
+ void (*reset)(CPUAlphaState *env);
+ /* Uncorrectable hardware error */
+ void (*machine_check)(CPUAlphaState *env);
+ /* Arithmetic exception */
+ void (*arithmetic)(CPUAlphaState *env);
+ /* Interrupt / correctable hardware error */
+ void (*interrupt)(CPUAlphaState *env);
+ /* Data fault */
+ void (*dfault)(CPUAlphaState *env);
+ /* DTB miss pal */
+ void (*dtb_miss_pal)(CPUAlphaState *env);
+ /* DTB miss native */
+ void (*dtb_miss_native)(CPUAlphaState *env);
+ /* Unaligned access */
+ void (*unalign)(CPUAlphaState *env);
+ /* ITB miss */
+ void (*itb_miss)(CPUAlphaState *env);
+ /* Instruction stream access violation */
+ void (*itb_acv)(CPUAlphaState *env);
+ /* Reserved or privileged opcode */
+ void (*opcdec)(CPUAlphaState *env);
+ /* Floating point exception */
+ void (*fen)(CPUAlphaState *env);
+ /* Call pal instruction */
+ void (*call_pal)(CPUAlphaState *env, uint32_t palcode);
+};
+
+struct CPUAlphaState {
+ uint64_t ir[31];
+ float64 fir[31];
+ float_status fp_status;
+ uint64_t fpcr;
+ uint64_t pc;
+ uint64_t lock;
+ uint32_t pcc[2];
+ uint64_t ipr[IPR_LAST];
+ uint64_t ps;
+ uint64_t unique;
+ int saved_mode; /* Used for HW_LD / HW_ST */
+
+#if TARGET_LONG_BITS > HOST_LONG_BITS
+ /* temporary fixed-point registers
+ * used to emulate 64 bits target on 32 bits hosts
+ */
+ target_ulong t0, t1, t2;
+#endif
+ /* */
+ double ft0, ft1, ft2;
+
+ /* Those resources are used only in Qemu core */
+ CPU_COMMON
+
+ jmp_buf jmp_env;
+ int user_mode_only; /* user mode only simulation */
+ uint32_t hflags;
+ int halted;
+
+ int exception_index;
+ int error_code;
+ int interrupt_request;
+
+ uint32_t features;
+ uint32_t amask;
+ int implver;
+ pal_handler_t *pal_handler;
+};
+
+#include "cpu-all.h"
+
+enum {
+ FEATURE_ASN = 0x00000001,
+ FEATURE_SPS = 0x00000002,
+ FEATURE_VIRBND = 0x00000004,
+ FEATURE_TBCHK = 0x00000008,
+};
+
+enum {
+ EXCP_RESET = 0x0000,
+ EXCP_MCHK = 0x0020,
+ EXCP_ARITH = 0x0060,
+ EXCP_HW_INTERRUPT = 0x00E0,
+ EXCP_DFAULT = 0x01E0,
+ EXCP_DTB_MISS_PAL = 0x09E0,
+ EXCP_ITB_MISS = 0x03E0,
+ EXCP_ITB_ACV = 0x07E0,
+ EXCP_DTB_MISS_NATIVE = 0x08E0,
+ EXCP_UNALIGN = 0x11E0,
+ EXCP_OPCDEC = 0x13E0,
+ EXCP_FEN = 0x17E0,
+ EXCP_CALL_PAL = 0x2000,
+ EXCP_CALL_PALP = 0x3000,
+ EXCP_CALL_PALE = 0x4000,
+ /* Pseudo exception for console */
+ EXCP_CONSOLE_DISPATCH = 0x4001,
+ EXCP_CONSOLE_FIXUP = 0x4002,
+};
+
+/* Arithmetic exception */
+enum {
+ EXCP_ARITH_OVERFLOW,
+};
+
+enum {
+ PALCODE_CALL = 0x00000000,
+ PALCODE_LD = 0x01000000,
+ PALCODE_ST = 0x02000000,
+ PALCODE_MFPR = 0x03000000,
+ PALCODE_MTPR = 0x04000000,
+ PALCODE_REI = 0x05000000,
+ PALCODE_INIT = 0xF0000000,
+};
+
+enum {
+ IR_V0 = 0,
+ IR_T0 = 1,
+ IR_T1 = 2,
+ IR_T2 = 3,
+ IR_T3 = 4,
+ IR_T4 = 5,
+ IR_T5 = 6,
+ IR_T6 = 7,
+ IR_T7 = 8,
+ IR_S0 = 9,
+ IR_S1 = 10,
+ IR_S2 = 11,
+ IR_S3 = 12,
+ IR_S4 = 13,
+ IR_S5 = 14,
+ IR_S6 = 15,
+#define IR_FP IR_S6
+ IR_A0 = 16,
+ IR_A1 = 17,
+ IR_A2 = 18,
+ IR_A3 = 19,
+ IR_A4 = 20,
+ IR_A5 = 21,
+ IR_T8 = 22,
+ IR_T9 = 23,
+ IR_T10 = 24,
+ IR_T11 = 25,
+ IR_RA = 26,
+ IR_T12 = 27,
+#define IR_PV IR_T12
+ IR_AT = 28,
+ IR_GP = 29,
+ IR_SP = 30,
+ IR_ZERO = 31,
+};
+
+CPUAlphaState * cpu_alpha_init (void);
+int cpu_alpha_exec(CPUAlphaState *s);
+/* you can call this signal handler from your SIGBUS and SIGSEGV
+ signal handlers to inform the virtual CPU of exceptions. non zero
+ is returned if the signal was handled by the virtual CPU. */
+int cpu_alpha_signal_handler(int host_signum, void *pinfo,
+ void *puc);
+int cpu_alpha_mfpr (CPUState *env, int iprn, uint64_t *valp);
+int cpu_alpha_mtpr (CPUState *env, int iprn, uint64_t val, uint64_t *oldvalp);
+void cpu_loop_exit (void);
+void pal_init (CPUState *env);
+void call_pal (CPUState *env, int palcode);
+
+#endif /* !defined (__CPU_ALPHA_H__) */
Added: trunk/src/host/qemu-neo1973/target-alpha/exec.h
===================================================================
--- trunk/src/host/qemu-neo1973/target-alpha/exec.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/target-alpha/exec.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,82 @@
+/*
+ * Alpha emulation cpu run-time definitions for qemu.
+ *
+ * Copyright (c) 2007 Jocelyn Mayer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if !defined (__ALPHA_EXEC_H__)
+#define __ALPHA_EXEC_H__
+
+#include "config.h"
+
+#include "dyngen-exec.h"
+
+#define TARGET_LONG_BITS 64
+
+register struct CPUAlphaState *env asm(AREG0);
+
+#if TARGET_LONG_BITS > HOST_LONG_BITS
+
+/* no registers can be used */
+#define T0 (env->t0)
+#define T1 (env->t1)
+#define T2 (env->t2)
+
+#else
+
+register uint64_t T0 asm(AREG1);
+register uint64_t T1 asm(AREG2);
+register uint64_t T2 asm(AREG3);
+
+#endif /* TARGET_LONG_BITS > HOST_LONG_BITS */
+
+#define PARAM(n) ((uint64_t)PARAM##n)
+#define SPARAM(n) ((int32_t)PARAM##n)
+#define FT0 (env->ft0)
+#define FT1 (env->ft1)
+#define FT2 (env->ft2)
+#define FP_STATUS (env->fp_status)
+
+#if defined (DEBUG_OP)
+#define RETURN() __asm__ __volatile__("nop" : : : "memory");
+#else
+#define RETURN() __asm__ __volatile__("" : : : "memory");
+#endif
+
+#include "cpu.h"
+#include "exec-all.h"
+
+#if !defined(CONFIG_USER_ONLY)
+#include "softmmu_exec.h"
+#endif /* !defined(CONFIG_USER_ONLY) */
+
+static inline void env_to_regs(void)
+{
+}
+
+static inline void regs_to_env(void)
+{
+}
+
+int cpu_alpha_handle_mmu_fault (CPUState *env, uint64_t address, int rw,
+ int is_user, int is_softmmu);
+int cpu_alpha_mfpr (CPUState *env, int iprn, uint64_t *valp);
+int cpu_alpha_mtpr (CPUState *env, int iprn, uint64_t val, uint64_t *oldvalp);
+
+void do_interrupt (CPUState *env);
+
+#endif /* !defined (__ALPHA_EXEC_H__) */
Added: trunk/src/host/qemu-neo1973/target-alpha/helper.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-alpha/helper.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/target-alpha/helper.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,454 @@
+/*
+ * Alpha emulation cpu helpers for qemu.
+ *
+ * Copyright (c) 2007 Jocelyn Mayer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "cpu.h"
+#include "exec-all.h"
+
+#if defined(CONFIG_USER_ONLY)
+
+int cpu_alpha_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
+ int is_user, int is_softmmu)
+{
+ if (rw == 2)
+ env->exception_index = EXCP_ITB_MISS;
+ else
+ env->exception_index = EXCP_DFAULT;
+ env->ipr[IPR_EXC_ADDR] = address;
+
+ return 1;
+}
+
+target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr)
+{
+ return addr;
+}
+
+void do_interrupt (CPUState *env)
+{
+ env->exception_index = -1;
+}
+
+#else
+
+target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr)
+{
+ return -1;
+}
+
+int cpu_alpha_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
+ int is_user, int is_softmmu)
+{
+ uint32_t opc;
+
+ if (rw == 2) {
+ /* Instruction translation buffer miss */
+ env->exception_index = EXCP_ITB_MISS;
+ } else {
+ if (env->ipr[IPR_EXC_ADDR] & 1)
+ env->exception_index = EXCP_DTB_MISS_PAL;
+ else
+ env->exception_index = EXCP_DTB_MISS_NATIVE;
+ opc = (ldl_code(env->pc) >> 21) << 4;
+ if (rw) {
+ opc |= 0x9;
+ } else {
+ opc |= 0x4;
+ }
+ env->ipr[IPR_MM_STAT] = opc;
+ }
+
+ return 1;
+}
+
+int cpu_alpha_mfpr (CPUState *env, int iprn, uint64_t *valp)
+{
+ uint64_t hwpcb;
+ int ret = 0;
+
+ hwpcb = env->ipr[IPR_PCBB];
+ switch (iprn) {
+ case IPR_ASN:
+ if (env->features & FEATURE_ASN)
+ *valp = env->ipr[IPR_ASN];
+ else
+ *valp = 0;
+ break;
+ case IPR_ASTEN:
+ *valp = ((int64_t)(env->ipr[IPR_ASTEN] << 60)) >> 60;
+ break;
+ case IPR_ASTSR:
+ *valp = ((int64_t)(env->ipr[IPR_ASTSR] << 60)) >> 60;
+ break;
+ case IPR_DATFX:
+ /* Write only */
+ ret = -1;
+ break;
+ case IPR_ESP:
+ if (env->features & FEATURE_SPS)
+ *valp = env->ipr[IPR_ESP];
+ else
+ *valp = ldq_raw(hwpcb + 8);
+ break;
+ case IPR_FEN:
+ *valp = ((int64_t)(env->ipr[IPR_FEN] << 63)) >> 63;
+ break;
+ case IPR_IPIR:
+ /* Write-only */
+ ret = -1;
+ break;
+ case IPR_IPL:
+ *valp = ((int64_t)(env->ipr[IPR_IPL] << 59)) >> 59;
+ break;
+ case IPR_KSP:
+ if (!(env->ipr[IPR_EXC_ADDR] & 1)) {
+ ret = -1;
+ } else {
+ if (env->features & FEATURE_SPS)
+ *valp = env->ipr[IPR_KSP];
+ else
+ *valp = ldq_raw(hwpcb + 0);
+ }
+ break;
+ case IPR_MCES:
+ *valp = ((int64_t)(env->ipr[IPR_MCES] << 59)) >> 59;
+ break;
+ case IPR_PERFMON:
+ /* Implementation specific */
+ *valp = 0;
+ break;
+ case IPR_PCBB:
+ *valp = ((int64_t)env->ipr[IPR_PCBB] << 16) >> 16;
+ break;
+ case IPR_PRBR:
+ *valp = env->ipr[IPR_PRBR];
+ break;
+ case IPR_PTBR:
+ *valp = env->ipr[IPR_PTBR];
+ break;
+ case IPR_SCBB:
+ *valp = (int64_t)((int32_t)env->ipr[IPR_SCBB]);
+ break;
+ case IPR_SIRR:
+ /* Write-only */
+ ret = -1;
+ break;
+ case IPR_SISR:
+ *valp = (int64_t)((int16_t)env->ipr[IPR_SISR]);
+ case IPR_SSP:
+ if (env->features & FEATURE_SPS)
+ *valp = env->ipr[IPR_SSP];
+ else
+ *valp = ldq_raw(hwpcb + 16);
+ break;
+ case IPR_SYSPTBR:
+ if (env->features & FEATURE_VIRBND)
+ *valp = env->ipr[IPR_SYSPTBR];
+ else
+ ret = -1;
+ break;
+ case IPR_TBCHK:
+ if ((env->features & FEATURE_TBCHK)) {
+ /* XXX: TODO */
+ *valp = 0;
+ ret = -1;
+ } else {
+ ret = -1;
+ }
+ break;
+ case IPR_TBIA:
+ /* Write-only */
+ ret = -1;
+ break;
+ case IPR_TBIAP:
+ /* Write-only */
+ ret = -1;
+ break;
+ case IPR_TBIS:
+ /* Write-only */
+ ret = -1;
+ break;
+ case IPR_TBISD:
+ /* Write-only */
+ ret = -1;
+ break;
+ case IPR_TBISI:
+ /* Write-only */
+ ret = -1;
+ break;
+ case IPR_USP:
+ if (env->features & FEATURE_SPS)
+ *valp = env->ipr[IPR_USP];
+ else
+ *valp = ldq_raw(hwpcb + 24);
+ break;
+ case IPR_VIRBND:
+ if (env->features & FEATURE_VIRBND)
+ *valp = env->ipr[IPR_VIRBND];
+ else
+ ret = -1;
+ break;
+ case IPR_VPTB:
+ *valp = env->ipr[IPR_VPTB];
+ break;
+ case IPR_WHAMI:
+ *valp = env->ipr[IPR_WHAMI];
+ break;
+ default:
+ /* Invalid */
+ ret = -1;
+ break;
+ }
+
+ return ret;
+}
+
+int cpu_alpha_mtpr (CPUState *env, int iprn, uint64_t val, uint64_t *oldvalp)
+{
+ uint64_t hwpcb, tmp64;
+ uint8_t tmp8;
+ int ret = 0;
+
+ hwpcb = env->ipr[IPR_PCBB];
+ switch (iprn) {
+ case IPR_ASN:
+ /* Read-only */
+ ret = -1;
+ break;
+ case IPR_ASTEN:
+ tmp8 = ((int8_t)(env->ipr[IPR_ASTEN] << 4)) >> 4;
+ *oldvalp = tmp8;
+ tmp8 &= val & 0xF;
+ tmp8 |= (val >> 4) & 0xF;
+ env->ipr[IPR_ASTEN] &= ~0xF;
+ env->ipr[IPR_ASTEN] |= tmp8;
+ ret = 1;
+ break;
+ case IPR_ASTSR:
+ tmp8 = ((int8_t)(env->ipr[IPR_ASTSR] << 4)) >> 4;
+ *oldvalp = tmp8;
+ tmp8 &= val & 0xF;
+ tmp8 |= (val >> 4) & 0xF;
+ env->ipr[IPR_ASTSR] &= ~0xF;
+ env->ipr[IPR_ASTSR] |= tmp8;
+ ret = 1;
+ case IPR_DATFX:
+ env->ipr[IPR_DATFX] &= ~0x1;
+ env->ipr[IPR_DATFX] |= val & 1;
+ tmp64 = ldq_raw(hwpcb + 56);
+ tmp64 &= ~0x8000000000000000ULL;
+ tmp64 |= (val & 1) << 63;
+ stq_raw(hwpcb + 56, tmp64);
+ break;
+ case IPR_ESP:
+ if (env->features & FEATURE_SPS)
+ env->ipr[IPR_ESP] = val;
+ else
+ stq_raw(hwpcb + 8, val);
+ break;
+ case IPR_FEN:
+ env->ipr[IPR_FEN] = val & 1;
+ tmp64 = ldq_raw(hwpcb + 56);
+ tmp64 &= ~1;
+ tmp64 |= val & 1;
+ stq_raw(hwpcb + 56, tmp64);
+ break;
+ case IPR_IPIR:
+ /* XXX: TODO: Send IRQ to CPU #ir[16] */
+ break;
+ case IPR_IPL:
+ *oldvalp = ((int64_t)(env->ipr[IPR_IPL] << 59)) >> 59;
+ env->ipr[IPR_IPL] &= ~0x1F;
+ env->ipr[IPR_IPL] |= val & 0x1F;
+ /* XXX: may issue an interrupt or ASR _now_ */
+ ret = 1;
+ break;
+ case IPR_KSP:
+ if (!(env->ipr[IPR_EXC_ADDR] & 1)) {
+ ret = -1;
+ } else {
+ if (env->features & FEATURE_SPS)
+ env->ipr[IPR_KSP] = val;
+ else
+ stq_raw(hwpcb + 0, val);
+ }
+ break;
+ case IPR_MCES:
+ env->ipr[IPR_MCES] &= ~((val & 0x7) | 0x18);
+ env->ipr[IPR_MCES] |= val & 0x18;
+ break;
+ case IPR_PERFMON:
+ /* Implementation specific */
+ *oldvalp = 0;
+ ret = 1;
+ break;
+ case IPR_PCBB:
+ /* Read-only */
+ ret = -1;
+ break;
+ case IPR_PRBR:
+ env->ipr[IPR_PRBR] = val;
+ break;
+ case IPR_PTBR:
+ /* Read-only */
+ ret = -1;
+ break;
+ case IPR_SCBB:
+ env->ipr[IPR_SCBB] = (uint32_t)val;
+ break;
+ case IPR_SIRR:
+ if (val & 0xF) {
+ env->ipr[IPR_SISR] |= 1 << (val & 0xF);
+ /* XXX: request a software interrupt _now_ */
+ }
+ break;
+ case IPR_SISR:
+ /* Read-only */
+ ret = -1;
+ break;
+ case IPR_SSP:
+ if (env->features & FEATURE_SPS)
+ env->ipr[IPR_SSP] = val;
+ else
+ stq_raw(hwpcb + 16, val);
+ break;
+ case IPR_SYSPTBR:
+ if (env->features & FEATURE_VIRBND)
+ env->ipr[IPR_SYSPTBR] = val;
+ else
+ ret = -1;
+ case IPR_TBCHK:
+ /* Read-only */
+ ret = -1;
+ break;
+ case IPR_TBIA:
+ tlb_flush(env, 1);
+ break;
+ case IPR_TBIAP:
+ tlb_flush(env, 1);
+ break;
+ case IPR_TBIS:
+ tlb_flush_page(env, val);
+ break;
+ case IPR_TBISD:
+ tlb_flush_page(env, val);
+ break;
+ case IPR_TBISI:
+ tlb_flush_page(env, val);
+ break;
+ case IPR_USP:
+ if (env->features & FEATURE_SPS)
+ env->ipr[IPR_USP] = val;
+ else
+ stq_raw(hwpcb + 24, val);
+ break;
+ case IPR_VIRBND:
+ if (env->features & FEATURE_VIRBND)
+ env->ipr[IPR_VIRBND] = val;
+ else
+ ret = -1;
+ break;
+ case IPR_VPTB:
+ env->ipr[IPR_VPTB] = val;
+ break;
+ case IPR_WHAMI:
+ /* Read-only */
+ ret = -1;
+ break;
+ default:
+ /* Invalid */
+ ret = -1;
+ break;
+ }
+
+ return ret;
+}
+
+void do_interrupt (CPUState *env)
+{
+ int excp;
+
+ env->ipr[IPR_EXC_ADDR] = env->pc | 1;
+ excp = env->exception_index;
+ env->exception_index = 0;
+ env->error_code = 0;
+ /* XXX: disable interrupts and memory mapping */
+ if (env->ipr[IPR_PAL_BASE] != -1ULL) {
+ /* We use native PALcode */
+ env->pc = env->ipr[IPR_PAL_BASE] + excp;
+ } else {
+ /* We use emulated PALcode */
+ call_pal(env);
+ /* Emulate REI */
+ env->pc = env->ipr[IPR_EXC_ADDR] & ~7;
+ env->ipr[IPR_EXC_ADDR] = env->ipr[IPR_EXC_ADDR] & 1;
+ /* XXX: re-enable interrupts and memory mapping */
+ }
+}
+#endif
+
+void cpu_dump_state (CPUState *env, FILE *f,
+ int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
+ int flags)
+{
+ static unsigned char *linux_reg_names[] = {
+ "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",
+ };
+ int i;
+
+ cpu_fprintf(f, " PC " TARGET_FMT_lx " PS " TARGET_FMT_lx "\n",
+ env->pc, env->ps);
+ for (i = 0; i < 31; i++) {
+ cpu_fprintf(f, "IR%02d %s " TARGET_FMT_lx " ", i,
+ linux_reg_names[i], env->ir[i]);
+ if ((i % 3) == 2)
+ cpu_fprintf(f, "\n");
+ }
+ cpu_fprintf(f, "\n");
+ for (i = 0; i < 31; i++) {
+ cpu_fprintf(f, "FIR%02d " TARGET_FMT_lx " ", i,
+ *((uint64_t *)(&env->fir[i])));
+ if ((i % 3) == 2)
+ cpu_fprintf(f, "\n");
+ }
+ cpu_fprintf(f, "FT " TARGET_FMT_lx " " TARGET_FMT_lx " " TARGET_FMT_lx,
+ *((uint64_t *)(&env->ft0)), *((uint64_t *)(&env->ft1)),
+ *((uint64_t *)(&env->ft2)));
+ cpu_fprintf(f, "\nMEM " TARGET_FMT_lx " %d %d\n",
+ ldq_raw(0x000000004007df60ULL),
+ (uint8_t *)(&env->ft0), (uint8_t *)(&env->fir[0]));
+}
+
+void cpu_dump_EA (target_ulong EA)
+{
+ FILE *f;
+
+ if (logfile)
+ f = logfile;
+ else
+ f = stdout;
+ fprintf(f, "Memory access at address " TARGET_FMT_lx "\n", EA);
+}
Added: trunk/src/host/qemu-neo1973/target-alpha/op.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-alpha/op.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/target-alpha/op.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,1103 @@
+/*
+ * Alpha emulation cpu micro-operations for qemu.
+ *
+ * Copyright (c) 2007 Jocelyn Mayer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define DEBUG_OP
+
+#include "config.h"
+#include "exec.h"
+
+#include "op_helper.h"
+
+#define REG 0
+#include "op_template.h"
+
+#define REG 1
+#include "op_template.h"
+
+#define REG 2
+#include "op_template.h"
+
+#define REG 3
+#include "op_template.h"
+
+#define REG 4
+#include "op_template.h"
+
+#define REG 5
+#include "op_template.h"
+
+#define REG 6
+#include "op_template.h"
+
+#define REG 7
+#include "op_template.h"
+
+#define REG 8
+#include "op_template.h"
+
+#define REG 9
+#include "op_template.h"
+
+#define REG 10
+#include "op_template.h"
+
+#define REG 11
+#include "op_template.h"
+
+#define REG 12
+#include "op_template.h"
+
+#define REG 13
+#include "op_template.h"
+
+#define REG 14
+#include "op_template.h"
+
+#define REG 15
+#include "op_template.h"
+
+#define REG 16
+#include "op_template.h"
+
+#define REG 17
+#include "op_template.h"
+
+#define REG 18
+#include "op_template.h"
+
+#define REG 19
+#include "op_template.h"
+
+#define REG 20
+#include "op_template.h"
+
+#define REG 21
+#include "op_template.h"
+
+#define REG 22
+#include "op_template.h"
+
+#define REG 23
+#include "op_template.h"
+
+#define REG 24
+#include "op_template.h"
+
+#define REG 25
+#include "op_template.h"
+
+#define REG 26
+#include "op_template.h"
+
+#define REG 27
+#include "op_template.h"
+
+#define REG 28
+#include "op_template.h"
+
+#define REG 29
+#include "op_template.h"
+
+#define REG 30
+#include "op_template.h"
+
+#define REG 31
+#include "op_template.h"
+
+/* Debug stuff */
+void OPPROTO op_no_op (void)
+{
+#if !defined (DEBUG_OP)
+ __asm__ __volatile__("nop" : : : "memory");
+#endif
+ RETURN();
+}
+
+void OPPROTO op_tb_flush (void)
+{
+ helper_tb_flush();
+ RETURN();
+}
+
+/* Load and stores */
+#define MEMSUFFIX _raw
+#include "op_mem.h"
+#if !defined(CONFIG_USER_ONLY)
+#define MEMSUFFIX _user
+#include "op_mem.h"
+#define MEMSUFFIX _kernel
+#include "op_mem.h"
+/* Those are used for supervisor, executive and pal modes */
+#define MEMSUFFIX _data
+#include "op_mem.h"
+#endif
+
+/* Special operation for load and store */
+void OPPROTO op_n7 (void)
+{
+ T0 &= ~(uint64_t)0x7;
+ RETURN();
+}
+
+/* Misc */
+void OPPROTO op_excp (void)
+{
+ helper_excp(PARAM(1), PARAM(2));
+ RETURN();
+}
+
+void OPPROTO op_load_amask (void)
+{
+ helper_amask();
+ RETURN();
+}
+
+void OPPROTO op_load_pcc (void)
+{
+ helper_load_pcc();
+ RETURN();
+}
+
+void OPPROTO op_load_implver (void)
+{
+ helper_load_implver();
+ RETURN();
+}
+
+void OPPROTO op_load_fpcr (void)
+{
+ helper_load_fpcr();
+ RETURN();
+}
+
+void OPPROTO op_store_fpcr (void)
+{
+ helper_store_fpcr();
+ RETURN();
+}
+
+void OPPROTO op_load_irf (void)
+{
+ helper_load_irf();
+ RETURN();
+}
+
+void OPPROTO op_set_irf (void)
+{
+ helper_set_irf();
+ RETURN();
+}
+
+void OPPROTO op_clear_irf (void)
+{
+ helper_clear_irf();
+ RETURN();
+}
+
+void OPPROTO op_exit_tb (void)
+{
+ EXIT_TB();
+}
+
+/* Arithmetic */
+void OPPROTO op_addq (void)
+{
+ T0 += T1;
+ RETURN();
+}
+
+void OPPROTO op_addqv (void)
+{
+ helper_addqv();
+ RETURN();
+}
+
+void OPPROTO op_addl (void)
+{
+ T0 = (int64_t)((int32_t)(T0 + T1));
+ RETURN();
+}
+
+void OPPROTO op_addlv (void)
+{
+ helper_addlv();
+ RETURN();
+}
+
+void OPPROTO op_subq (void)
+{
+ T0 -= T1;
+ RETURN();
+}
+
+void OPPROTO op_subqv (void)
+{
+ helper_subqv();
+ RETURN();
+}
+
+void OPPROTO op_subl (void)
+{
+ T0 = (int64_t)((int32_t)(T0 - T1));
+ RETURN();
+}
+
+void OPPROTO op_sublv (void)
+{
+ helper_sublv();
+ RETURN();
+}
+
+void OPPROTO op_s4 (void)
+{
+ T0 <<= 2;
+ RETURN();
+}
+
+void OPPROTO op_s8 (void)
+{
+ T0 <<= 3;
+ RETURN();
+}
+
+void OPPROTO op_mull (void)
+{
+ T0 = (int64_t)((int32_t)T0 * (int32_t)T1);
+ RETURN();
+}
+
+void OPPROTO op_mullv (void)
+{
+ helper_mullv();
+ RETURN();
+}
+
+void OPPROTO op_mulq (void)
+{
+ T0 *= T1;
+ RETURN();
+}
+
+void OPPROTO op_mulqv (void)
+{
+ helper_mulqv();
+ RETURN();
+}
+
+void OPPROTO op_umulh (void)
+{
+ helper_umulh();
+ RETURN();
+}
+
+/* Logical */
+void OPPROTO op_and (void)
+{
+ T0 &= T1;
+ RETURN();
+}
+
+void OPPROTO op_bic (void)
+{
+ T0 &= ~T1;
+ RETURN();
+}
+
+void OPPROTO op_bis (void)
+{
+ T0 |= T1;
+ RETURN();
+}
+
+void OPPROTO op_eqv (void)
+{
+ T0 ^= ~T1;
+ RETURN();
+}
+
+void OPPROTO op_ornot (void)
+{
+ T0 |= ~T1;
+ RETURN();
+}
+
+void OPPROTO op_xor (void)
+{
+ T0 ^= T1;
+ RETURN();
+}
+
+void OPPROTO op_sll (void)
+{
+ T0 <<= T1;
+ RETURN();
+}
+
+void OPPROTO op_srl (void)
+{
+ T0 >>= T1;
+ RETURN();
+}
+
+void OPPROTO op_sra (void)
+{
+ T0 = (int64_t)T0 >> T1;
+ RETURN();
+}
+
+void OPPROTO op_sextb (void)
+{
+ T0 = (int64_t)((int8_t)T0);
+ RETURN();
+}
+
+void OPPROTO op_sextw (void)
+{
+ T0 = (int64_t)((int16_t)T0);
+ RETURN();
+
+}
+
+void OPPROTO op_ctpop (void)
+{
+ helper_ctpop();
+ RETURN();
+}
+
+void OPPROTO op_ctlz (void)
+{
+ helper_ctlz();
+ RETURN();
+}
+
+void OPPROTO op_cttz (void)
+{
+ helper_cttz();
+ RETURN();
+}
+
+void OPPROTO op_mskbl (void)
+{
+ helper_mskbl();
+ RETURN();
+}
+
+void OPPROTO op_extbl (void)
+{
+ helper_extbl();
+ RETURN();
+}
+
+void OPPROTO op_insbl (void)
+{
+ helper_insbl();
+ RETURN();
+}
+
+void OPPROTO op_mskwl (void)
+{
+ helper_mskwl();
+ RETURN();
+}
+
+void OPPROTO op_extwl (void)
+{
+ helper_extwl();
+ RETURN();
+}
+
+void OPPROTO op_inswl (void)
+{
+ helper_inswl();
+ RETURN();
+}
+
+void OPPROTO op_mskll (void)
+{
+ helper_mskll();
+ RETURN();
+}
+
+void OPPROTO op_extll (void)
+{
+ helper_extll();
+ RETURN();
+}
+
+void OPPROTO op_insll (void)
+{
+ helper_insll();
+ RETURN();
+}
+
+void OPPROTO op_zap (void)
+{
+ helper_zap();
+ RETURN();
+}
+
+void OPPROTO op_zapnot (void)
+{
+ helper_zapnot();
+ RETURN();
+}
+
+void OPPROTO op_mskql (void)
+{
+ helper_mskql();
+ RETURN();
+}
+
+void OPPROTO op_extql (void)
+{
+ helper_extql();
+ RETURN();
+}
+
+void OPPROTO op_insql (void)
+{
+ helper_insql();
+ RETURN();
+}
+
+void OPPROTO op_mskwh (void)
+{
+ helper_mskwh();
+ RETURN();
+}
+
+void OPPROTO op_inswh (void)
+{
+ helper_inswh();
+ RETURN();
+}
+
+void OPPROTO op_extwh (void)
+{
+ helper_extwh();
+ RETURN();
+}
+
+void OPPROTO op_msklh (void)
+{
+ helper_msklh();
+ RETURN();
+}
+
+void OPPROTO op_inslh (void)
+{
+ helper_inslh();
+ RETURN();
+}
+
+void OPPROTO op_extlh (void)
+{
+ helper_extlh();
+ RETURN();
+}
+
+void OPPROTO op_mskqh (void)
+{
+ helper_mskqh();
+ RETURN();
+}
+
+void OPPROTO op_insqh (void)
+{
+ helper_insqh();
+ RETURN();
+}
+
+void OPPROTO op_extqh (void)
+{
+ helper_extqh();
+ RETURN();
+}
+
+/* Tests */
+void OPPROTO op_cmpult (void)
+{
+ if (T0 < T1)
+ T0 = 1;
+ else
+ T0 = 0;
+ RETURN();
+}
+
+void OPPROTO op_cmpule (void)
+{
+ if (T0 <= T1)
+ T0 = 1;
+ else
+ T0 = 0;
+ RETURN();
+}
+
+void OPPROTO op_cmpeq (void)
+{
+ if (T0 == T1)
+ T0 = 1;
+ else
+ T0 = 0;
+ RETURN();
+}
+
+void OPPROTO op_cmplt (void)
+{
+ if ((int64_t)T0 < (int64_t)T1)
+ T0 = 1;
+ else
+ T0 = 0;
+ RETURN();
+}
+
+void OPPROTO op_cmple (void)
+{
+ if ((int64_t)T0 <= (int64_t)T1)
+ T0 = 1;
+ else
+ T0 = 0;
+ RETURN();
+}
+
+void OPPROTO op_cmpbge (void)
+{
+ helper_cmpbge();
+ RETURN();
+}
+
+void OPPROTO op_cmpeqz (void)
+{
+ if (T0 == 0)
+ T0 = 1;
+ else
+ T0 = 0;
+ RETURN();
+}
+
+void OPPROTO op_cmpnez (void)
+{
+ if (T0 != 0)
+ T0 = 1;
+ else
+ T0 = 0;
+ RETURN();
+}
+
+void OPPROTO op_cmpltz (void)
+{
+ if ((int64_t)T0 < 0)
+ T0 = 1;
+ else
+ T0 = 0;
+ RETURN();
+}
+
+void OPPROTO op_cmplez (void)
+{
+ if ((int64_t)T0 <= 0)
+ T0 = 1;
+ else
+ T0 = 0;
+ RETURN();
+}
+
+void OPPROTO op_cmpgtz (void)
+{
+ if ((int64_t)T0 > 0)
+ T0 = 1;
+ else
+ T0 = 0;
+ RETURN();
+}
+
+void OPPROTO op_cmpgez (void)
+{
+ if ((int64_t)T0 >= 0)
+ T0 = 1;
+ else
+ T0 = 0;
+ RETURN();
+}
+
+void OPPROTO op_cmplbs (void)
+{
+ T0 &= 1;
+ RETURN();
+}
+
+void OPPROTO op_cmplbc (void)
+{
+ T0 = (~T0) & 1;
+ RETURN();
+}
+
+/* Branches */
+void OPPROTO op_branch (void)
+{
+ env->pc = T0 & ~3;
+ RETURN();
+}
+
+void OPPROTO op_addq1 (void)
+{
+ T1 += T0;
+ RETURN();
+}
+
+#if 0 // Qemu does not know how to do this...
+void OPPROTO op_bcond (void)
+{
+ if (T0)
+ env->pc = T1 & ~3;
+ else
+ env->pc = PARAM(1);
+ RETURN();
+}
+#else
+void OPPROTO op_bcond (void)
+{
+ if (T0)
+ env->pc = T1 & ~3;
+ else
+ env->pc = ((uint64_t)PARAM(1) << 32) | (uint64_t)PARAM(2);
+ RETURN();
+}
+#endif
+
+#if 0 // Qemu does not know how to do this...
+void OPPROTO op_update_pc (void)
+{
+ env->pc = PARAM(1);
+ RETURN();
+}
+#else
+void OPPROTO op_update_pc (void)
+{
+ env->pc = ((uint64_t)PARAM(1) << 32) | (uint64_t)PARAM(2);
+ RETURN();
+}
+#endif
+
+/* Optimization for 32 bits hosts architectures */
+void OPPROTO op_update_pc32 (void)
+{
+ env->pc = (uint64_t)PARAM(1);
+ RETURN();
+}
+
+/* IEEE floating point arithmetic */
+/* S floating (single) */
+void OPPROTO op_adds (void)
+{
+ FT0 = float32_add(FT0, FT1, &FP_STATUS);
+ RETURN();
+}
+
+void OPPROTO op_subs (void)
+{
+ FT0 = float32_sub(FT0, FT1, &FP_STATUS);
+ RETURN();
+}
+
+void OPPROTO op_muls (void)
+{
+ FT0 = float32_mul(FT0, FT1, &FP_STATUS);
+ RETURN();
+}
+
+void OPPROTO op_divs (void)
+{
+ FT0 = float32_div(FT0, FT1, &FP_STATUS);
+ RETURN();
+}
+
+void OPPROTO op_sqrts (void)
+{
+ helper_sqrts();
+ RETURN();
+}
+
+void OPPROTO op_cpys (void)
+{
+ helper_cpys();
+ RETURN();
+}
+
+void OPPROTO op_cpysn (void)
+{
+ helper_cpysn();
+ RETURN();
+}
+
+void OPPROTO op_cpyse (void)
+{
+ helper_cpyse();
+ RETURN();
+}
+
+void OPPROTO op_itofs (void)
+{
+ helper_itofs();
+ RETURN();
+}
+
+void OPPROTO op_ftois (void)
+{
+ helper_ftois();
+ RETURN();
+}
+
+/* T floating (double) */
+void OPPROTO op_addt (void)
+{
+ FT0 = float64_add(FT0, FT1, &FP_STATUS);
+ RETURN();
+}
+
+void OPPROTO op_subt (void)
+{
+ FT0 = float64_sub(FT0, FT1, &FP_STATUS);
+ RETURN();
+}
+
+void OPPROTO op_mult (void)
+{
+ FT0 = float64_mul(FT0, FT1, &FP_STATUS);
+ RETURN();
+}
+
+void OPPROTO op_divt (void)
+{
+ FT0 = float64_div(FT0, FT1, &FP_STATUS);
+ RETURN();
+}
+
+void OPPROTO op_sqrtt (void)
+{
+ helper_sqrtt();
+ RETURN();
+}
+
+void OPPROTO op_cmptun (void)
+{
+ helper_cmptun();
+ RETURN();
+}
+
+void OPPROTO op_cmpteq (void)
+{
+ helper_cmpteq();
+ RETURN();
+}
+
+void OPPROTO op_cmptle (void)
+{
+ helper_cmptle();
+ RETURN();
+}
+
+void OPPROTO op_cmptlt (void)
+{
+ helper_cmptlt();
+ RETURN();
+}
+
+void OPPROTO op_itoft (void)
+{
+ helper_itoft();
+ RETURN();
+}
+
+void OPPROTO op_ftoit (void)
+{
+ helper_ftoit();
+ RETURN();
+}
+
+/* VAX floating point arithmetic */
+/* F floating */
+void OPPROTO op_addf (void)
+{
+ helper_addf();
+ RETURN();
+}
+
+void OPPROTO op_subf (void)
+{
+ helper_subf();
+ RETURN();
+}
+
+void OPPROTO op_mulf (void)
+{
+ helper_mulf();
+ RETURN();
+}
+
+void OPPROTO op_divf (void)
+{
+ helper_divf();
+ RETURN();
+}
+
+void OPPROTO op_sqrtf (void)
+{
+ helper_sqrtf();
+ RETURN();
+}
+
+void OPPROTO op_cmpfeq (void)
+{
+ helper_cmpfeq();
+ RETURN();
+}
+
+void OPPROTO op_cmpfne (void)
+{
+ helper_cmpfne();
+ RETURN();
+}
+
+void OPPROTO op_cmpflt (void)
+{
+ helper_cmpflt();
+ RETURN();
+}
+
+void OPPROTO op_cmpfle (void)
+{
+ helper_cmpfle();
+ RETURN();
+}
+
+void OPPROTO op_cmpfgt (void)
+{
+ helper_cmpfgt();
+ RETURN();
+}
+
+void OPPROTO op_cmpfge (void)
+{
+ helper_cmpfge();
+ RETURN();
+}
+
+void OPPROTO op_itoff (void)
+{
+ helper_itoff();
+ RETURN();
+}
+
+/* G floating */
+void OPPROTO op_addg (void)
+{
+ helper_addg();
+ RETURN();
+}
+
+void OPPROTO op_subg (void)
+{
+ helper_subg();
+ RETURN();
+}
+
+void OPPROTO op_mulg (void)
+{
+ helper_mulg();
+ RETURN();
+}
+
+void OPPROTO op_divg (void)
+{
+ helper_divg();
+ RETURN();
+}
+
+void OPPROTO op_sqrtg (void)
+{
+ helper_sqrtg();
+ RETURN();
+}
+
+void OPPROTO op_cmpgeq (void)
+{
+ helper_cmpgeq();
+ RETURN();
+}
+
+void OPPROTO op_cmpglt (void)
+{
+ helper_cmpglt();
+ RETURN();
+}
+
+void OPPROTO op_cmpgle (void)
+{
+ helper_cmpgle();
+ RETURN();
+}
+
+/* Floating point format conversion */
+void OPPROTO op_cvtst (void)
+{
+ FT0 = (float)FT0;
+ RETURN();
+}
+
+void OPPROTO op_cvtqs (void)
+{
+ helper_cvtqs();
+ RETURN();
+}
+
+void OPPROTO op_cvtts (void)
+{
+ FT0 = (float)FT0;
+ RETURN();
+}
+
+void OPPROTO op_cvttq (void)
+{
+ helper_cvttq();
+ RETURN();
+}
+
+void OPPROTO op_cvtqt (void)
+{
+ helper_cvtqt();
+ RETURN();
+}
+
+void OPPROTO op_cvtqf (void)
+{
+ helper_cvtqf();
+ RETURN();
+}
+
+void OPPROTO op_cvtgf (void)
+{
+ helper_cvtgf();
+ RETURN();
+}
+
+void OPPROTO op_cvtgd (void)
+{
+ helper_cvtgd();
+ RETURN();
+}
+
+void OPPROTO op_cvtgq (void)
+{
+ helper_cvtgq();
+ RETURN();
+}
+
+void OPPROTO op_cvtqg (void)
+{
+ helper_cvtqg();
+ RETURN();
+}
+
+void OPPROTO op_cvtdg (void)
+{
+ helper_cvtdg();
+ RETURN();
+}
+
+void OPPROTO op_cvtlq (void)
+{
+ helper_cvtlq();
+ RETURN();
+}
+
+void OPPROTO op_cvtql (void)
+{
+ helper_cvtql();
+ RETURN();
+}
+
+void OPPROTO op_cvtqlv (void)
+{
+ helper_cvtqlv();
+ RETURN();
+}
+
+void OPPROTO op_cvtqlsv (void)
+{
+ helper_cvtqlsv();
+ RETURN();
+}
+
+/* PALcode support special instructions */
+#if !defined (CONFIG_USER_ONLY)
+void OPPROTO op_hw_rei (void)
+{
+ env->pc = env->ipr[IPR_EXC_ADDR] & ~3;
+ env->ipr[IPR_EXC_ADDR] = env->ipr[IPR_EXC_ADDR] & 1;
+ /* XXX: re-enable interrupts and memory mapping */
+ RETURN();
+}
+
+void OPPROTO op_hw_ret (void)
+{
+ env->pc = T0 & ~3;
+ env->ipr[IPR_EXC_ADDR] = T0 & 1;
+ /* XXX: re-enable interrupts and memory mapping */
+ RETURN();
+}
+
+void OPPROTO op_mfpr (void)
+{
+ helper_mfpr(PARAM(1));
+ RETURN();
+}
+
+void OPPROTO op_mtpr (void)
+{
+ helper_mtpr(PARAM(1));
+ RETURN();
+}
+
+void OPPROTO op_set_alt_mode (void)
+{
+ env->saved_mode = env->ps & 0xC;
+ env->ps = (env->ps & ~0xC) | (env->ipr[IPR_ALT_MODE] & 0xC);
+ RETURN();
+}
+
+void OPPROTO op_restore_mode (void)
+{
+ env->ps = (env->ps & ~0xC) | env->saved_mode;
+ RETURN();
+}
+
+void OPPROTO op_ld_phys_to_virt (void)
+{
+ helper_ld_phys_to_virt();
+ RETURN();
+}
+
+void OPPROTO op_st_phys_to_virt (void)
+{
+ helper_st_phys_to_virt();
+ RETURN();
+}
+#endif /* !defined (CONFIG_USER_ONLY) */
Added: trunk/src/host/qemu-neo1973/target-alpha/op_helper.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-alpha/op_helper.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/target-alpha/op_helper.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,1255 @@
+/*
+ * Alpha emulation cpu micro-operations helpers for qemu.
+ *
+ * Copyright (c) 2007 Jocelyn Mayer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "exec.h"
+#include "softfloat.h"
+
+#include "op_helper.h"
+
+#define MEMSUFFIX _raw
+#include "op_helper_mem.h"
+
+#if !defined(CONFIG_USER_ONLY)
+#define MEMSUFFIX _user
+#include "op_helper_mem.h"
+
+#define MEMSUFFIX _kernel
+#include "op_helper_mem.h"
+
+/* Those are used for supervisor and executive modes */
+#define MEMSUFFIX _data
+#include "op_helper_mem.h"
+#endif
+
+void helper_tb_flush (void)
+{
+ tlb_flush(env, 1);
+}
+
+void cpu_dump_EA (target_ulong EA);
+void helper_print_mem_EA (target_ulong EA)
+{
+ cpu_dump_EA(EA);
+}
+
+/*****************************************************************************/
+/* Exceptions processing helpers */
+void helper_excp (uint32_t excp, uint32_t error)
+{
+ env->exception_index = excp;
+ env->error_code = error;
+ cpu_loop_exit();
+}
+
+void helper_amask (void)
+{
+ switch (env->implver) {
+ case IMPLVER_2106x:
+ /* EV4, EV45, LCA, LCA45 & EV5 */
+ break;
+ case IMPLVER_21164:
+ case IMPLVER_21264:
+ case IMPLVER_21364:
+ T0 &= ~env->amask;
+ break;
+ }
+}
+
+void helper_load_pcc (void)
+{
+ /* XXX: TODO */
+ T0 = 0;
+}
+
+void helper_load_implver (void)
+{
+ T0 = env->implver;
+}
+
+void helper_load_fpcr (void)
+{
+ T0 = 0;
+#ifdef CONFIG_SOFTFLOAT
+ T0 |= env->fp_status.float_exception_flags << 52;
+ if (env->fp_status.float_exception_flags)
+ T0 |= 1ULL << 63;
+ env->ipr[IPR_EXC_SUM] &= ~0x3E:
+ env->ipr[IPR_EXC_SUM] |= env->fp_status.float_exception_flags << 1;
+#endif
+ switch (env->fp_status.float_rounding_mode) {
+ case float_round_nearest_even:
+ T0 |= 2ULL << 58;
+ break;
+ case float_round_down:
+ T0 |= 1ULL << 58;
+ break;
+ case float_round_up:
+ T0 |= 3ULL << 58;
+ break;
+ case float_round_to_zero:
+ break;
+ }
+}
+
+void helper_store_fpcr (void)
+{
+#ifdef CONFIG_SOFTFLOAT
+ set_float_exception_flags((T0 >> 52) & 0x3F, &FP_STATUS);
+#endif
+ switch ((T0 >> 58) & 3) {
+ case 0:
+ set_float_rounding_mode(float_round_to_zero, &FP_STATUS);
+ break;
+ case 1:
+ set_float_rounding_mode(float_round_down, &FP_STATUS);
+ break;
+ case 2:
+ set_float_rounding_mode(float_round_nearest_even, &FP_STATUS);
+ break;
+ case 3:
+ set_float_rounding_mode(float_round_up, &FP_STATUS);
+ break;
+ }
+}
+
+void helper_load_irf (void)
+{
+ /* XXX: TODO */
+ T0 = 0;
+}
+
+void helper_set_irf (void)
+{
+ /* XXX: TODO */
+}
+
+void helper_clear_irf (void)
+{
+ /* XXX: TODO */
+}
+
+void helper_addqv (void)
+{
+ T2 = T0;
+ T0 += T1;
+ if (unlikely((T2 ^ T1 ^ (-1ULL)) & (T2 ^ T0) & (1ULL << 63))) {
+ helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW);
+ }
+}
+
+void helper_addlv (void)
+{
+ T2 = T0;
+ T0 = (uint32_t)(T0 + T1);
+ if (unlikely((T2 ^ T1 ^ (-1UL)) & (T2 ^ T0) & (1UL << 31))) {
+ helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW);
+ }
+}
+
+void helper_subqv (void)
+{
+ T2 = T0;
+ T0 -= T1;
+ if (unlikely(((~T2) ^ T0 ^ (-1ULL)) & ((~T2) ^ T1) & (1ULL << 63))) {
+ helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW);
+ }
+}
+
+void helper_sublv (void)
+{
+ T2 = T0;
+ T0 = (uint32_t)(T0 - T1);
+ if (unlikely(((~T2) ^ T0 ^ (-1UL)) & ((~T2) ^ T1) & (1UL << 31))) {
+ helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW);
+ }
+}
+
+void helper_mullv (void)
+{
+ int64_t res = (int64_t)T0 * (int64_t)T1;
+
+ if (unlikely((int32_t)res != res)) {
+ helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW);
+ }
+ T0 = (int64_t)((int32_t)res);
+}
+
+void helper_mulqv ()
+{
+ uint64_t res, tmp0, tmp1;
+
+ res = (T0 >> 32) * (T1 >> 32);
+ tmp0 = ((T0 & 0xFFFFFFFF) * (T1 >> 32)) +
+ ((T0 >> 32) * (T1 & 0xFFFFFFFF));
+ tmp1 = (T0 & 0xFFFFFFFF) * (T1 & 0xFFFFFFFF);
+ tmp0 += tmp1 >> 32;
+ res += tmp0 >> 32;
+ T0 *= T1;
+ if (unlikely(res != 0)) {
+ helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW);
+ }
+}
+
+void helper_umulh (void)
+{
+ uint64_t tmp0, tmp1;
+
+ tmp0 = ((T0 & 0xFFFFFFFF) * (T1 >> 32)) +
+ ((T0 >> 32) * (T1 & 0xFFFFFFFF));
+ tmp1 = (T0 & 0xFFFFFFFF) * (T1 & 0xFFFFFFFF);
+ tmp0 += tmp1 >> 32;
+ T0 = (T0 >> 32) * (T0 >> 32);
+ T0 += tmp0 >> 32;
+}
+
+void helper_ctpop (void)
+{
+ int n;
+
+ for (n = 0; T0 != 0; n++)
+ T0 = T0 ^ (T0 - 1);
+ T0 = n;
+}
+
+void helper_ctlz (void)
+{
+ uint32_t op32;
+ int n;
+
+ n = 0;
+ if (!(T0 & 0xFFFFFFFF00000000ULL)) {
+ n += 32;
+ T0 <<= 32;
+ }
+ /* Make it easier for 32 bits hosts */
+ op32 = T0 >> 32;
+ if (!(op32 & 0xFFFF0000UL)) {
+ n += 16;
+ op32 <<= 16;
+ }
+ if (!(op32 & 0xFF000000UL)) {
+ n += 8;
+ op32 <<= 8;
+ }
+ if (!(op32 & 0xF0000000UL)) {
+ n += 4;
+ op32 <<= 4;
+ }
+ if (!(op32 & 0xC0000000UL)) {
+ n += 2;
+ op32 <<= 2;
+ }
+ if (!(op32 & 0x80000000UL)) {
+ n++;
+ op32 <<= 1;
+ }
+ if (!(op32 & 0x80000000UL)) {
+ n++;
+ }
+ T0 = n;
+}
+
+void helper_cttz (void)
+{
+ uint32_t op32;
+ int n;
+
+ n = 0;
+ if (!(T0 & 0x00000000FFFFFFFFULL)) {
+ n += 32;
+ T0 >>= 32;
+ }
+ /* Make it easier for 32 bits hosts */
+ op32 = T0;
+ if (!(op32 & 0x0000FFFFUL)) {
+ n += 16;
+ op32 >>= 16;
+ }
+ if (!(op32 & 0x000000FFUL)) {
+ n += 8;
+ op32 >>= 8;
+ }
+ if (!(op32 & 0x0000000FUL)) {
+ n += 4;
+ op32 >>= 4;
+ }
+ if (!(op32 & 0x00000003UL)) {
+ n += 2;
+ op32 >>= 2;
+ }
+ if (!(op32 & 0x00000001UL)) {
+ n++;
+ op32 >>= 1;
+ }
+ if (!(op32 & 0x00000001UL)) {
+ n++;
+ }
+ T0 = n;
+}
+
+static inline uint64_t byte_zap (uint64_t op, uint8_t mskb)
+{
+ uint64_t mask;
+
+ mask = 0;
+ mask |= ((mskb >> 0) & 1) * 0x00000000000000FFULL;
+ mask |= ((mskb >> 1) & 1) * 0x000000000000FF00ULL;
+ mask |= ((mskb >> 2) & 1) * 0x0000000000FF0000ULL;
+ mask |= ((mskb >> 3) & 1) * 0x00000000FF000000ULL;
+ mask |= ((mskb >> 4) & 1) * 0x000000FF00000000ULL;
+ mask |= ((mskb >> 5) & 1) * 0x0000FF0000000000ULL;
+ mask |= ((mskb >> 6) & 1) * 0x00FF000000000000ULL;
+ mask |= ((mskb >> 7) & 1) * 0xFF00000000000000ULL;
+
+ return op & ~mask;
+}
+
+void helper_mskbl (void)
+{
+ T0 = byte_zap(T0, 0x01 << (T1 & 7));
+}
+
+void helper_extbl (void)
+{
+ T0 >>= (T1 & 7) * 8;
+ T0 = byte_zap(T0, 0xFE);
+}
+
+void helper_insbl (void)
+{
+ T0 <<= (T1 & 7) * 8;
+ T0 = byte_zap(T0, ~(0x01 << (T1 & 7)));
+}
+
+void helper_mskwl (void)
+{
+ T0 = byte_zap(T0, 0x03 << (T1 & 7));
+}
+
+void helper_extwl (void)
+{
+ T0 >>= (T1 & 7) * 8;
+ T0 = byte_zap(T0, 0xFC);
+}
+
+void helper_inswl (void)
+{
+ T0 <<= (T1 & 7) * 8;
+ T0 = byte_zap(T0, ~(0x03 << (T1 & 7)));
+}
+
+void helper_mskll (void)
+{
+ T0 = byte_zap(T0, 0x0F << (T1 & 7));
+}
+
+void helper_extll (void)
+{
+ T0 >>= (T1 & 7) * 8;
+ T0 = byte_zap(T0, 0xF0);
+}
+
+void helper_insll (void)
+{
+ T0 <<= (T1 & 7) * 8;
+ T0 = byte_zap(T0, ~(0x0F << (T1 & 7)));
+}
+
+void helper_zap (void)
+{
+ T0 = byte_zap(T0, T1);
+}
+
+void helper_zapnot (void)
+{
+ T0 = byte_zap(T0, ~T1);
+}
+
+void helper_mskql (void)
+{
+ T0 = byte_zap(T0, 0xFF << (T1 & 7));
+}
+
+void helper_extql (void)
+{
+ T0 >>= (T1 & 7) * 8;
+ T0 = byte_zap(T0, 0x00);
+}
+
+void helper_insql (void)
+{
+ T0 <<= (T1 & 7) * 8;
+ T0 = byte_zap(T0, ~(0xFF << (T1 & 7)));
+}
+
+void helper_mskwh (void)
+{
+ T0 = byte_zap(T0, (0x03 << (T1 & 7)) >> 8);
+}
+
+void helper_inswh (void)
+{
+ T0 >>= 64 - ((T1 & 7) * 8);
+ T0 = byte_zap(T0, ~((0x03 << (T1 & 7)) >> 8));
+}
+
+void helper_extwh (void)
+{
+ T0 <<= 64 - ((T1 & 7) * 8);
+ T0 = byte_zap(T0, ~0x07);
+}
+
+void helper_msklh (void)
+{
+ T0 = byte_zap(T0, (0x0F << (T1 & 7)) >> 8);
+}
+
+void helper_inslh (void)
+{
+ T0 >>= 64 - ((T1 & 7) * 8);
+ T0 = byte_zap(T0, ~((0x0F << (T1 & 7)) >> 8));
+}
+
+void helper_extlh (void)
+{
+ T0 <<= 64 - ((T1 & 7) * 8);
+ T0 = byte_zap(T0, ~0x0F);
+}
+
+void helper_mskqh (void)
+{
+ T0 = byte_zap(T0, (0xFF << (T1 & 7)) >> 8);
+}
+
+void helper_insqh (void)
+{
+ T0 >>= 64 - ((T1 & 7) * 8);
+ T0 = byte_zap(T0, ~((0xFF << (T1 & 7)) >> 8));
+}
+
+void helper_extqh (void)
+{
+ T0 <<= 64 - ((T1 & 7) * 8);
+ T0 = byte_zap(T0, 0x00);
+}
+
+void helper_cmpbge (void)
+{
+ uint8_t opa, opb, res;
+ int i;
+
+ res = 0;
+ for (i = 0; i < 7; i++) {
+ opa = T0 >> (i * 8);
+ opb = T1 >> (i * 8);
+ if (opa >= opb)
+ res |= 1 << i;
+ }
+ T0 = res;
+}
+
+void helper_cmov_fir (int freg)
+{
+ if (FT0 != 0)
+ env->fir[freg] = FT1;
+}
+
+void helper_sqrts (void)
+{
+ FT0 = float32_sqrt(FT0, &FP_STATUS);
+}
+
+void helper_cpys (void)
+{
+ union {
+ double d;
+ uint64_t i;
+ } p, q, r;
+
+ p.d = FT0;
+ q.d = FT1;
+ r.i = p.i & 0x8000000000000000ULL;
+ r.i |= q.i & ~0x8000000000000000ULL;
+ FT0 = r.d;
+}
+
+void helper_cpysn (void)
+{
+ union {
+ double d;
+ uint64_t i;
+ } p, q, r;
+
+ p.d = FT0;
+ q.d = FT1;
+ r.i = (~p.i) & 0x8000000000000000ULL;
+ r.i |= q.i & ~0x8000000000000000ULL;
+ FT0 = r.d;
+}
+
+void helper_cpyse (void)
+{
+ union {
+ double d;
+ uint64_t i;
+ } p, q, r;
+
+ p.d = FT0;
+ q.d = FT1;
+ r.i = p.i & 0xFFF0000000000000ULL;
+ r.i |= q.i & ~0xFFF0000000000000ULL;
+ FT0 = r.d;
+}
+
+void helper_itofs (void)
+{
+ union {
+ double d;
+ uint64_t i;
+ } p;
+
+ p.d = FT0;
+ FT0 = int64_to_float32(p.i, &FP_STATUS);
+}
+
+void helper_ftois (void)
+{
+ union {
+ double d;
+ uint64_t i;
+ } p;
+
+ p.i = float32_to_int64(FT0, &FP_STATUS);
+ FT0 = p.d;
+}
+
+void helper_sqrtt (void)
+{
+ FT0 = float64_sqrt(FT0, &FP_STATUS);
+}
+
+void helper_cmptun (void)
+{
+ union {
+ double d;
+ uint64_t i;
+ } p;
+
+ p.i = 0;
+ if (float64_is_nan(FT0) || float64_is_nan(FT1))
+ p.i = 0x4000000000000000ULL;
+ FT0 = p.d;
+}
+
+void helper_cmpteq (void)
+{
+ union {
+ double d;
+ uint64_t i;
+ } p;
+
+ p.i = 0;
+ if (float64_eq(FT0, FT1, &FP_STATUS))
+ p.i = 0x4000000000000000ULL;
+ FT0 = p.d;
+}
+
+void helper_cmptle (void)
+{
+ union {
+ double d;
+ uint64_t i;
+ } p;
+
+ p.i = 0;
+ if (float64_le(FT0, FT1, &FP_STATUS))
+ p.i = 0x4000000000000000ULL;
+ FT0 = p.d;
+}
+
+void helper_cmptlt (void)
+{
+ union {
+ double d;
+ uint64_t i;
+ } p;
+
+ p.i = 0;
+ if (float64_lt(FT0, FT1, &FP_STATUS))
+ p.i = 0x4000000000000000ULL;
+ FT0 = p.d;
+}
+
+void helper_itoft (void)
+{
+ union {
+ double d;
+ uint64_t i;
+ } p;
+
+ p.d = FT0;
+ FT0 = int64_to_float64(p.i, &FP_STATUS);
+}
+
+void helper_ftoit (void)
+{
+ union {
+ double d;
+ uint64_t i;
+ } p;
+
+ p.i = float64_to_int64(FT0, &FP_STATUS);
+ FT0 = p.d;
+}
+
+static int vaxf_is_valid (float ff)
+{
+ union {
+ float f;
+ uint32_t i;
+ } p;
+ uint32_t exp, mant;
+
+ p.f = ff;
+ exp = (p.i >> 23) & 0xFF;
+ mant = p.i & 0x007FFFFF;
+ if (exp == 0 && ((p.i & 0x80000000) || mant != 0)) {
+ /* Reserved operands / Dirty zero */
+ return 0;
+ }
+
+ return 1;
+}
+
+static float vaxf_to_ieee32 (float ff)
+{
+ union {
+ float f;
+ uint32_t i;
+ } p;
+ uint32_t exp;
+
+ p.f = ff;
+ exp = (p.i >> 23) & 0xFF;
+ if (exp < 3) {
+ /* Underflow */
+ p.f = 0.0;
+ } else {
+ p.f *= 0.25;
+ }
+
+ return p.f;
+}
+
+static float ieee32_to_vaxf (float fi)
+{
+ union {
+ float f;
+ uint32_t i;
+ } p;
+ uint32_t exp, mant;
+
+ p.f = fi;
+ exp = (p.i >> 23) & 0xFF;
+ mant = p.i & 0x007FFFFF;
+ if (exp == 255) {
+ /* NaN or infinity */
+ p.i = 1;
+ } else if (exp == 0) {
+ if (mant == 0) {
+ /* Zero */
+ p.i = 0;
+ } else {
+ /* Denormalized */
+ p.f *= 2.0;
+ }
+ } else {
+ if (exp >= 253) {
+ /* Overflow */
+ p.i = 1;
+ } else {
+ p.f *= 4.0;
+ }
+ }
+
+ return p.f;
+}
+
+void helper_addf (void)
+{
+ float ft0, ft1, ft2;
+
+ if (!vaxf_is_valid(FT0) || !vaxf_is_valid(FT1)) {
+ /* XXX: TODO */
+ }
+ ft0 = vaxf_to_ieee32(FT0);
+ ft1 = vaxf_to_ieee32(FT1);
+ ft2 = float32_add(ft0, ft1, &FP_STATUS);
+ FT0 = ieee32_to_vaxf(ft2);
+}
+
+void helper_subf (void)
+{
+ float ft0, ft1, ft2;
+
+ if (!vaxf_is_valid(FT0) || !vaxf_is_valid(FT1)) {
+ /* XXX: TODO */
+ }
+ ft0 = vaxf_to_ieee32(FT0);
+ ft1 = vaxf_to_ieee32(FT1);
+ ft2 = float32_sub(ft0, ft1, &FP_STATUS);
+ FT0 = ieee32_to_vaxf(ft2);
+}
+
+void helper_mulf (void)
+{
+ float ft0, ft1, ft2;
+
+ if (!vaxf_is_valid(FT0) || !vaxf_is_valid(FT1)) {
+ /* XXX: TODO */
+ }
+ ft0 = vaxf_to_ieee32(FT0);
+ ft1 = vaxf_to_ieee32(FT1);
+ ft2 = float32_mul(ft0, ft1, &FP_STATUS);
+ FT0 = ieee32_to_vaxf(ft2);
+}
+
+void helper_divf (void)
+{
+ float ft0, ft1, ft2;
+
+ if (!vaxf_is_valid(FT0) || !vaxf_is_valid(FT1)) {
+ /* XXX: TODO */
+ }
+ ft0 = vaxf_to_ieee32(FT0);
+ ft1 = vaxf_to_ieee32(FT1);
+ ft2 = float32_div(ft0, ft1, &FP_STATUS);
+ FT0 = ieee32_to_vaxf(ft2);
+}
+
+void helper_sqrtf (void)
+{
+ float ft0, ft1;
+
+ if (!vaxf_is_valid(FT0) || !vaxf_is_valid(FT1)) {
+ /* XXX: TODO */
+ }
+ ft0 = vaxf_to_ieee32(FT0);
+ ft1 = float32_sqrt(ft0, &FP_STATUS);
+ FT0 = ieee32_to_vaxf(ft1);
+}
+
+void helper_itoff (void)
+{
+ /* XXX: TODO */
+}
+
+static int vaxg_is_valid (double ff)
+{
+ union {
+ double f;
+ uint64_t i;
+ } p;
+ uint64_t exp, mant;
+
+ p.f = ff;
+ exp = (p.i >> 52) & 0x7FF;
+ mant = p.i & 0x000FFFFFFFFFFFFFULL;
+ if (exp == 0 && ((p.i & 0x8000000000000000ULL) || mant != 0)) {
+ /* Reserved operands / Dirty zero */
+ return 0;
+ }
+
+ return 1;
+}
+
+static double vaxg_to_ieee64 (double fg)
+{
+ union {
+ double f;
+ uint64_t i;
+ } p;
+ uint32_t exp;
+
+ p.f = fg;
+ exp = (p.i >> 52) & 0x7FF;
+ if (exp < 3) {
+ /* Underflow */
+ p.f = 0.0;
+ } else {
+ p.f *= 0.25;
+ }
+
+ return p.f;
+}
+
+static double ieee64_to_vaxg (double fi)
+{
+ union {
+ double f;
+ uint64_t i;
+ } p;
+ uint64_t mant;
+ uint32_t exp;
+
+ p.f = fi;
+ exp = (p.i >> 52) & 0x7FF;
+ mant = p.i & 0x000FFFFFFFFFFFFFULL;
+ if (exp == 255) {
+ /* NaN or infinity */
+ p.i = 1; /* VAX dirty zero */
+ } else if (exp == 0) {
+ if (mant == 0) {
+ /* Zero */
+ p.i = 0;
+ } else {
+ /* Denormalized */
+ p.f *= 2.0;
+ }
+ } else {
+ if (exp >= 2045) {
+ /* Overflow */
+ p.i = 1; /* VAX dirty zero */
+ } else {
+ p.f *= 4.0;
+ }
+ }
+
+ return p.f;
+}
+
+void helper_addg (void)
+{
+ double ft0, ft1, ft2;
+
+ if (!vaxg_is_valid(FT0) || !vaxg_is_valid(FT1)) {
+ /* XXX: TODO */
+ }
+ ft0 = vaxg_to_ieee64(FT0);
+ ft1 = vaxg_to_ieee64(FT1);
+ ft2 = float64_add(ft0, ft1, &FP_STATUS);
+ FT0 = ieee64_to_vaxg(ft2);
+}
+
+void helper_subg (void)
+{
+ double ft0, ft1, ft2;
+
+ if (!vaxg_is_valid(FT0) || !vaxg_is_valid(FT1)) {
+ /* XXX: TODO */
+ }
+ ft0 = vaxg_to_ieee64(FT0);
+ ft1 = vaxg_to_ieee64(FT1);
+ ft2 = float64_sub(ft0, ft1, &FP_STATUS);
+ FT0 = ieee64_to_vaxg(ft2);
+}
+
+void helper_mulg (void)
+{
+ double ft0, ft1, ft2;
+
+ if (!vaxg_is_valid(FT0) || !vaxg_is_valid(FT1)) {
+ /* XXX: TODO */
+ }
+ ft0 = vaxg_to_ieee64(FT0);
+ ft1 = vaxg_to_ieee64(FT1);
+ ft2 = float64_mul(ft0, ft1, &FP_STATUS);
+ FT0 = ieee64_to_vaxg(ft2);
+}
+
+void helper_divg (void)
+{
+ double ft0, ft1, ft2;
+
+ if (!vaxg_is_valid(FT0) || !vaxg_is_valid(FT1)) {
+ /* XXX: TODO */
+ }
+ ft0 = vaxg_to_ieee64(FT0);
+ ft1 = vaxg_to_ieee64(FT1);
+ ft2 = float64_div(ft0, ft1, &FP_STATUS);
+ FT0 = ieee64_to_vaxg(ft2);
+}
+
+void helper_sqrtg (void)
+{
+ double ft0, ft1;
+
+ if (!vaxg_is_valid(FT0) || !vaxg_is_valid(FT1)) {
+ /* XXX: TODO */
+ }
+ ft0 = vaxg_to_ieee64(FT0);
+ ft1 = float64_sqrt(ft0, &FP_STATUS);
+ FT0 = ieee64_to_vaxg(ft1);
+}
+
+void helper_cmpgeq (void)
+{
+ union {
+ double d;
+ uint64_t u;
+ } p;
+ double ft0, ft1;
+
+ if (!vaxg_is_valid(FT0) || !vaxg_is_valid(FT1)) {
+ /* XXX: TODO */
+ }
+ ft0 = vaxg_to_ieee64(FT0);
+ ft1 = vaxg_to_ieee64(FT1);
+ p.u = 0;
+ if (float64_eq(ft0, ft1, &FP_STATUS))
+ p.u = 0x4000000000000000ULL;
+ FT0 = p.d;
+}
+
+void helper_cmpglt (void)
+{
+ union {
+ double d;
+ uint64_t u;
+ } p;
+ double ft0, ft1;
+
+ if (!vaxg_is_valid(FT0) || !vaxg_is_valid(FT1)) {
+ /* XXX: TODO */
+ }
+ ft0 = vaxg_to_ieee64(FT0);
+ ft1 = vaxg_to_ieee64(FT1);
+ p.u = 0;
+ if (float64_lt(ft0, ft1, &FP_STATUS))
+ p.u = 0x4000000000000000ULL;
+ FT0 = p.d;
+}
+
+void helper_cmpgle (void)
+{
+ union {
+ double d;
+ uint64_t u;
+ } p;
+ double ft0, ft1;
+
+ if (!vaxg_is_valid(FT0) || !vaxg_is_valid(FT1)) {
+ /* XXX: TODO */
+ }
+ ft0 = vaxg_to_ieee64(FT0);
+ ft1 = vaxg_to_ieee64(FT1);
+ p.u = 0;
+ if (float64_le(ft0, ft1, &FP_STATUS))
+ p.u = 0x4000000000000000ULL;
+ FT0 = p.d;
+}
+
+void helper_cvtqs (void)
+{
+ union {
+ double d;
+ uint64_t u;
+ } p;
+
+ p.d = FT0;
+ FT0 = (float)p.u;
+}
+
+void helper_cvttq (void)
+{
+ union {
+ double d;
+ uint64_t u;
+ } p;
+
+ p.u = FT0;
+ FT0 = p.d;
+}
+
+void helper_cvtqt (void)
+{
+ union {
+ double d;
+ uint64_t u;
+ } p;
+
+ p.d = FT0;
+ FT0 = p.u;
+}
+
+void helper_cvtqf (void)
+{
+ union {
+ double d;
+ uint64_t u;
+ } p;
+
+ p.d = FT0;
+ FT0 = ieee32_to_vaxf(p.u);
+}
+
+void helper_cvtgf (void)
+{
+ double ft0;
+
+ ft0 = vaxg_to_ieee64(FT0);
+ FT0 = ieee32_to_vaxf(ft0);
+}
+
+void helper_cvtgd (void)
+{
+ /* XXX: TODO */
+}
+
+void helper_cvtgq (void)
+{
+ union {
+ double d;
+ uint64_t u;
+ } p;
+
+ p.u = vaxg_to_ieee64(FT0);
+ FT0 = p.d;
+}
+
+void helper_cvtqg (void)
+{
+ union {
+ double d;
+ uint64_t u;
+ } p;
+
+ p.d = FT0;
+ FT0 = ieee64_to_vaxg(p.u);
+}
+
+void helper_cvtdg (void)
+{
+ /* XXX: TODO */
+}
+
+void helper_cvtlq (void)
+{
+ union {
+ double d;
+ uint64_t u;
+ } p, q;
+
+ p.d = FT0;
+ q.u = (p.u >> 29) & 0x3FFFFFFF;
+ q.u |= (p.u >> 32);
+ q.u = (int64_t)((int32_t)q.u);
+ FT0 = q.d;
+}
+
+static inline void __helper_cvtql (int s, int v)
+{
+ union {
+ double d;
+ uint64_t u;
+ } p, q;
+
+ p.d = FT0;
+ q.u = ((uint64_t)(p.u & 0xC0000000)) << 32;
+ q.u |= ((uint64_t)(p.u & 0x7FFFFFFF)) << 29;
+ FT0 = q.d;
+ if (v && (int64_t)((int32_t)p.u) != (int64_t)p.u) {
+ helper_excp(EXCP_ARITH, EXCP_ARITH_OVERFLOW);
+ }
+ if (s) {
+ /* TODO */
+ }
+}
+
+void helper_cvtql (void)
+{
+ __helper_cvtql(0, 0);
+}
+
+void helper_cvtqlv (void)
+{
+ __helper_cvtql(0, 1);
+}
+
+void helper_cvtqlsv (void)
+{
+ __helper_cvtql(1, 1);
+}
+
+void helper_cmpfeq (void)
+{
+ if (float64_eq(FT0, FT1, &FP_STATUS))
+ T0 = 1;
+ else
+ T0 = 0;
+}
+
+void helper_cmpfne (void)
+{
+ if (float64_eq(FT0, FT1, &FP_STATUS))
+ T0 = 0;
+ else
+ T0 = 1;
+}
+
+void helper_cmpflt (void)
+{
+ if (float64_lt(FT0, FT1, &FP_STATUS))
+ T0 = 1;
+ else
+ T0 = 0;
+}
+
+void helper_cmpfle (void)
+{
+ if (float64_lt(FT0, FT1, &FP_STATUS))
+ T0 = 1;
+ else
+ T0 = 0;
+}
+
+void helper_cmpfgt (void)
+{
+ if (float64_le(FT0, FT1, &FP_STATUS))
+ T0 = 0;
+ else
+ T0 = 1;
+}
+
+void helper_cmpfge (void)
+{
+ if (float64_lt(FT0, FT1, &FP_STATUS))
+ T0 = 0;
+ else
+ T0 = 1;
+}
+
+#if !defined (CONFIG_USER_ONLY)
+void helper_mfpr (int iprn)
+{
+ uint64_t val;
+
+ if (cpu_alpha_mfpr(env, iprn, &val) == 0)
+ T0 = val;
+}
+
+void helper_mtpr (int iprn)
+{
+ cpu_alpha_mtpr(env, iprn, T0, NULL);
+}
+#endif
+
+/*****************************************************************************/
+/* Softmmu support */
+#if !defined (CONFIG_USER_ONLY)
+
+#define GETPC() (__builtin_return_address(0))
+
+/* XXX: the two following helpers are pure hacks.
+ * Hopefully, we emulate the PALcode, then we should never see
+ * HW_LD / HW_ST instructions.
+ */
+void helper_ld_phys_to_virt (void)
+{
+ uint64_t tlb_addr, physaddr;
+ int index, is_user;
+ void *retaddr;
+
+ is_user = (env->ps >> 3) & 3;
+ index = (T0 >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
+ redo:
+ tlb_addr = env->tlb_table[is_user][index].addr_read;
+ if ((T0 & TARGET_PAGE_MASK) ==
+ (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
+ physaddr = T0 + env->tlb_table[is_user][index].addend;
+ } else {
+ /* the page is not in the TLB : fill it */
+ retaddr = GETPC();
+ tlb_fill(T0, 0, is_user, retaddr);
+ goto redo;
+ }
+ T0 = physaddr;
+}
+
+void helper_st_phys_to_virt (void)
+{
+ uint64_t tlb_addr, physaddr;
+ int index, is_user;
+ void *retaddr;
+
+ is_user = (env->ps >> 3) & 3;
+ index = (T0 >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
+ redo:
+ tlb_addr = env->tlb_table[is_user][index].addr_write;
+ if ((T0 & TARGET_PAGE_MASK) ==
+ (tlb_addr & (TARGET_PAGE_MASK | TLB_INVALID_MASK))) {
+ physaddr = T0 + env->tlb_table[is_user][index].addend;
+ } else {
+ /* the page is not in the TLB : fill it */
+ retaddr = GETPC();
+ tlb_fill(T0, 1, is_user, retaddr);
+ goto redo;
+ }
+ T0 = physaddr;
+}
+
+#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 is_user, void *retaddr)
+{
+ TranslationBlock *tb;
+ CPUState *saved_env;
+ target_phys_addr_t 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_alpha_handle_mmu_fault(env, addr, is_write, is_user, 1);
+ if (!likely(ret == 0)) {
+ if (likely(retaddr)) {
+ /* now we have a real cpu fault */
+ pc = (target_phys_addr_t)retaddr;
+ tb = tb_find_pc(pc);
+ if (likely(tb)) {
+ /* the PC is inside the translated code. It means that we have
+ a virtual CPU fault */
+ cpu_restore_state(tb, env, pc, NULL);
+ }
+ }
+ /* Exception index and error code are already set */
+ cpu_loop_exit();
+ }
+ env = saved_env;
+}
+
+#endif
Added: trunk/src/host/qemu-neo1973/target-alpha/op_helper.h
===================================================================
--- trunk/src/host/qemu-neo1973/target-alpha/op_helper.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/target-alpha/op_helper.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,141 @@
+/*
+ * Alpha emulation cpu micro-operations helpers definitions for qemu.
+ *
+ * Copyright (c) 2007 Jocelyn Mayer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+void helper_call_pal (uint32_t palcode);
+void helper_excp (uint32_t excp, uint32_t error);
+void helper_amask (void);
+void helper_load_pcc (void);
+void helper_load_implver (void);
+void helper_load_fpcr (void);
+void helper_store_fpcr (void);
+void helper_load_irf (void);
+void helper_set_irf (void);
+void helper_clear_irf (void);
+void helper_addqv (void);
+void helper_addlv (void);
+void helper_subqv (void);
+void helper_sublv (void);
+void helper_mullv (void);
+void helper_mulqv (void);
+void helper_umulh (void);
+void helper_ctpop (void);
+void helper_ctlz (void);
+void helper_cttz (void);
+void helper_mskbl (void);
+void helper_extbl (void);
+void helper_insbl (void);
+void helper_mskwl (void);
+void helper_extwl (void);
+void helper_inswl (void);
+void helper_mskll (void);
+void helper_extll (void);
+void helper_insll (void);
+void helper_zap (void);
+void helper_zapnot (void);
+void helper_mskql (void);
+void helper_extql (void);
+void helper_insql (void);
+void helper_mskwh (void);
+void helper_inswh (void);
+void helper_extwh (void);
+void helper_msklh (void);
+void helper_inslh (void);
+void helper_extlh (void);
+void helper_mskqh (void);
+void helper_insqh (void);
+void helper_extqh (void);
+void helper_cmpbge (void);
+void helper_cmov_fir (int freg);
+
+double helper_ldff_raw (target_ulong ea);
+void helper_stff_raw (target_ulong ea, double op);
+double helper_ldfg_raw (target_ulong ea);
+void helper_stfg_raw (target_ulong ea, double op);
+#if !defined(CONFIG_USER_ONLY)
+double helper_ldff_user (target_ulong ea);
+void helper_stff_user (target_ulong ea, double op);
+double helper_ldff_kernel (target_ulong ea);
+void helper_stff_kernel (target_ulong ea, double op);
+double helper_ldff_data (target_ulong ea);
+void helper_stff_data (target_ulong ea, double op);
+double helper_ldfg_user (target_ulong ea);
+void helper_stfg_user (target_ulong ea, double op);
+double helper_ldfg_kernel (target_ulong ea);
+void helper_stfg_kernel (target_ulong ea, double op);
+double helper_ldfg_data (target_ulong ea);
+void helper_stfg_data (target_ulong ea, double op);
+#endif
+
+void helper_sqrts (void);
+void helper_cpys (void);
+void helper_cpysn (void);
+void helper_cpyse (void);
+void helper_itofs (void);
+void helper_ftois (void);
+
+void helper_sqrtt (void);
+void helper_cmptun (void);
+void helper_cmpteq (void);
+void helper_cmptle (void);
+void helper_cmptlt (void);
+void helper_itoft (void);
+void helper_ftoit (void);
+
+void helper_addf (void);
+void helper_subf (void);
+void helper_mulf (void);
+void helper_divf (void);
+void helper_sqrtf (void);
+void helper_cmpfeq (void);
+void helper_cmpfne (void);
+void helper_cmpflt (void);
+void helper_cmpfle (void);
+void helper_cmpfgt (void);
+void helper_cmpfge (void);
+void helper_itoff (void);
+
+void helper_addg (void);
+void helper_subg (void);
+void helper_mulg (void);
+void helper_divg (void);
+void helper_sqrtg (void);
+void helper_cmpgeq (void);
+void helper_cmpglt (void);
+void helper_cmpgle (void);
+
+void helper_cvtqs (void);
+void helper_cvttq (void);
+void helper_cvtqt (void);
+void helper_cvtqf (void);
+void helper_cvtgf (void);
+void helper_cvtgd (void);
+void helper_cvtgq (void);
+void helper_cvtqg (void);
+void helper_cvtdg (void);
+void helper_cvtlq (void);
+void helper_cvtql (void);
+void helper_cvtqlv (void);
+void helper_cvtqlsv (void);
+
+void helper_mfpr (int iprn);
+void helper_mtpr (int iprn);
+void helper_ld_phys_to_virt (void);
+void helper_st_phys_to_virt (void);
+void helper_tb_flush (void);
Added: trunk/src/host/qemu-neo1973/target-alpha/op_helper_mem.h
===================================================================
--- trunk/src/host/qemu-neo1973/target-alpha/op_helper_mem.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/target-alpha/op_helper_mem.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,40 @@
+/*
+ * Alpha emulation cpu micro-operations helpers for memory accesses for qemu.
+ *
+ * Copyright (c) 2007 Jocelyn Mayer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* XXX: TODO */
+double glue(helper_ldff, MEMSUFFIX) (target_ulong ea)
+{
+ return 0;
+}
+
+void glue(helper_stff, MEMSUFFIX) (target_ulong ea, double op)
+{
+}
+
+double glue(helper_ldfg, MEMSUFFIX) (target_ulong ea)
+{
+ return 0;
+}
+
+void glue(helper_stfg, MEMSUFFIX) (target_ulong ea, double op)
+{
+}
+
+#undef MEMSUFFIX
Added: trunk/src/host/qemu-neo1973/target-alpha/op_mem.h
===================================================================
--- trunk/src/host/qemu-neo1973/target-alpha/op_mem.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/target-alpha/op_mem.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,125 @@
+/*
+ * Alpha emulation cpu micro-operations for memory accesses for qemu.
+ *
+ * Copyright (c) 2007 Jocelyn Mayer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#define DEBUG_MEM_ACCESSES
+#if defined (DEBUG_MEM_ACCESSES)
+void helper_print_mem_EA (target_ulong EA);
+#define print_mem_EA(EA) do { helper_print_mem_EA(EA); } while (0)
+#else
+#define print_mem_EA(EA) do { } while (0)
+#endif
+
+static inline uint32_t glue(ldl_l, MEMSUFFIX) (target_ulong EA)
+{
+ env->lock = EA;
+
+ return glue(ldl, MEMSUFFIX)(EA);
+}
+
+static inline uint32_t glue(ldq_l, MEMSUFFIX) (target_ulong EA)
+{
+ env->lock = EA;
+
+ return glue(ldq, MEMSUFFIX)(EA);
+}
+
+static inline void glue(stl_c, MEMSUFFIX) (target_ulong EA, uint32_t data)
+{
+ if (EA == env->lock) {
+ glue(stl, MEMSUFFIX)(EA, data);
+ T0 = 0;
+ } else {
+ T0 = 1;
+ }
+ env->lock = -1;
+}
+
+static inline void glue(stq_c, MEMSUFFIX) (target_ulong EA, uint64_t data)
+{
+ if (EA == env->lock) {
+ glue(stq, MEMSUFFIX)(EA, data);
+ T0 = 0;
+ } else {
+ T0 = 1;
+ }
+ env->lock = -1;
+}
+
+#define ALPHA_LD_OP(name, op) \
+void OPPROTO glue(glue(op_ld, name), MEMSUFFIX) (void) \
+{ \
+ print_mem_EA(T0); \
+ T1 = glue(op, MEMSUFFIX)(T0); \
+ RETURN(); \
+}
+
+#define ALPHA_ST_OP(name, op) \
+void OPPROTO glue(glue(op_st, name), MEMSUFFIX) (void) \
+{ \
+ print_mem_EA(T0); \
+ glue(op, MEMSUFFIX)(T0, T1); \
+ RETURN(); \
+}
+
+ALPHA_LD_OP(bu, ldub);
+ALPHA_ST_OP(b, stb);
+ALPHA_LD_OP(wu, lduw);
+ALPHA_ST_OP(w, stw);
+ALPHA_LD_OP(l, ldl);
+ALPHA_ST_OP(l, stl);
+ALPHA_LD_OP(q, ldq);
+ALPHA_ST_OP(q, stq);
+
+ALPHA_LD_OP(q_u, ldq);
+ALPHA_ST_OP(q_u, stq);
+
+ALPHA_LD_OP(l_l, ldl_l);
+ALPHA_LD_OP(q_l, ldq_l);
+ALPHA_ST_OP(l_c, stl_c);
+ALPHA_ST_OP(q_c, stq_c);
+
+#define ALPHA_LDF_OP(name, op) \
+void OPPROTO glue(glue(op_ld, name), MEMSUFFIX) (void) \
+{ \
+ print_mem_EA(T0); \
+ FT1 = glue(op, MEMSUFFIX)(T0); \
+ RETURN(); \
+}
+
+#define ALPHA_STF_OP(name, op) \
+void OPPROTO glue(glue(op_st, name), MEMSUFFIX) (void) \
+{ \
+ print_mem_EA(T0); \
+ glue(op, MEMSUFFIX)(T0, FT1); \
+ RETURN(); \
+}
+
+ALPHA_LDF_OP(t, ldfq);
+ALPHA_STF_OP(t, stfq);
+ALPHA_LDF_OP(s, ldfl);
+ALPHA_STF_OP(s, stfl);
+
+/* VAX floating point */
+ALPHA_LDF_OP(f, helper_ldff);
+ALPHA_STF_OP(f, helper_stff);
+ALPHA_LDF_OP(g, helper_ldfg);
+ALPHA_STF_OP(g, helper_stfg);
+
+#undef MEMSUFFIX
Added: trunk/src/host/qemu-neo1973/target-alpha/op_template.h
===================================================================
--- trunk/src/host/qemu-neo1973/target-alpha/op_template.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/target-alpha/op_template.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,167 @@
+/*
+ * Alpha emulation cpu micro-operations templates for qemu.
+ *
+ * Copyright (c) 2007 Jocelyn Mayer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* Optimized constant loads */
+#if REG < 3
+void OPPROTO glue(op_reset_T, REG) (void)
+{
+ glue(T, REG) = 0;
+ RETURN();
+}
+
+void OPPROTO glue(op_reset_FT, REG) (void)
+{
+ glue(FT, REG) = 0;
+ RETURN();
+}
+
+/* XXX: This can be great on most RISC machines */
+#if !defined(__i386__) && !defined(__x86_64__)
+void OPPROTO glue(op_set_s16_T, REG) (void)
+{
+ glue(T, REG) = (int16_t)PARAM(1);
+ RETURN();
+}
+
+void OPPROTO glue(op_set_u16_T, REG) (void)
+{
+ glue(T, REG) = (uint16_t)PARAM(1);
+ RETURN();
+}
+#endif
+
+void OPPROTO glue(op_set_s32_T, REG) (void)
+{
+ glue(T, REG) = (int32_t)PARAM(1);
+ RETURN();
+}
+
+void OPPROTO glue(op_set_u32_T, REG) (void)
+{
+ glue(T, REG) = (uint32_t)PARAM(1);
+ RETURN();
+}
+
+#if 0 // Qemu does not know how to do this...
+void OPPROTO glue(op_set_64_T, REG) (void)
+{
+ glue(T, REG) = (int64_t)PARAM(1);
+ RETURN();
+}
+#else
+void OPPROTO glue(op_set_64_T, REG) (void)
+{
+ glue(T, REG) = ((int64_t)PARAM(1) << 32) | (int64_t)PARAM(2);
+ RETURN();
+}
+#endif
+
+#endif /* REG < 3 */
+
+/* Fixed-point register moves */
+#if REG < 31
+void OPPROTO glue(op_load_T0_ir, REG) (void)
+{
+ T0 = env->ir[REG];
+ RETURN();
+}
+
+void OPPROTO glue(op_load_T1_ir, REG) (void)
+{
+ T1 = env->ir[REG];
+ RETURN();
+}
+
+void OPPROTO glue(op_load_T2_ir, REG) (void)
+{
+ T2 = env->ir[REG];
+ RETURN();
+}
+
+void OPPROTO glue(op_store_T0_ir, REG) (void)
+{
+ env->ir[REG] = T0;
+ RETURN();
+}
+
+void OPPROTO glue(op_store_T1_ir, REG) (void)
+{
+ env->ir[REG] = T1;
+ RETURN();
+}
+
+void OPPROTO glue(op_store_T2_ir, REG) (void)
+{
+ env->ir[REG] = T2;
+ RETURN();
+}
+
+void OPPROTO glue(op_cmov_ir, REG) (void)
+{
+ if (T0)
+ env->ir[REG] = T1;
+ RETURN();
+}
+
+/* floating point registers moves */
+void OPPROTO glue(op_load_FT0_fir, REG) (void)
+{
+ FT0 = env->fir[REG];
+ RETURN();
+}
+
+void OPPROTO glue(op_load_FT1_fir, REG) (void)
+{
+ FT1 = env->fir[REG];
+ RETURN();
+}
+
+void OPPROTO glue(op_load_FT2_fir, REG) (void)
+{
+ FT2 = env->fir[REG];
+ RETURN();
+}
+
+void OPPROTO glue(op_store_FT0_fir, REG) (void)
+{
+ env->fir[REG] = FT0;
+ RETURN();
+}
+
+void OPPROTO glue(op_store_FT1_fir, REG) (void)
+{
+ env->fir[REG] = FT1;
+ RETURN();
+}
+
+void OPPROTO glue(op_store_FT2_fir, REG) (void)
+{
+ env->fir[REG] = FT2;
+ RETURN();
+}
+
+void OPPROTO glue(op_cmov_fir, REG) (void)
+{
+ helper_cmov_fir(REG);
+ RETURN();
+}
+#endif /* REG < 31 */
+
+#undef REG
Added: trunk/src/host/qemu-neo1973/target-alpha/translate.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-alpha/translate.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/target-alpha/translate.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,2118 @@
+/*
+ * Alpha emulation cpu translation for qemu.
+ *
+ * Copyright (c) 2007 Jocelyn Mayer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "cpu.h"
+#include "exec-all.h"
+#include "disas.h"
+
+#define DO_SINGLE_STEP
+#define GENERATE_NOP
+#define ALPHA_DEBUG_DISAS
+#define DO_TB_FLUSH
+
+typedef struct DisasContext DisasContext;
+struct DisasContext {
+ uint64_t pc;
+ int mem_idx;
+#if !defined (CONFIG_USER_ONLY)
+ int pal_mode;
+#endif
+ uint32_t amask;
+};
+
+#ifdef USE_DIRECT_JUMP
+#define TBPARAM(x)
+#else
+#define TBPARAM(x) (long)(x)
+#endif
+
+enum {
+#define DEF(s, n, copy_size) INDEX_op_ ## s,
+#include "opc.h"
+#undef DEF
+ NB_OPS,
+};
+
+static uint16_t *gen_opc_ptr;
+static uint32_t *gen_opparam_ptr;
+
+#include "gen-op.h"
+
+static inline void gen_op_nop (void)
+{
+#if defined(GENERATE_NOP)
+ gen_op_no_op();
+#endif
+}
+
+#define GEN32(func, NAME) \
+static GenOpFunc *NAME ## _table [32] = { \
+NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3, \
+NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \
+NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \
+NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15, \
+NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19, \
+NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23, \
+NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27, \
+NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31, \
+}; \
+static inline void func(int n) \
+{ \
+ NAME ## _table[n](); \
+}
+
+/* IR moves */
+/* Special hacks for ir31 */
+#define gen_op_load_T0_ir31 gen_op_reset_T0
+#define gen_op_load_T1_ir31 gen_op_reset_T1
+#define gen_op_load_T2_ir31 gen_op_reset_T2
+#define gen_op_store_T0_ir31 gen_op_nop
+#define gen_op_store_T1_ir31 gen_op_nop
+#define gen_op_store_T2_ir31 gen_op_nop
+#define gen_op_cmov_ir31 gen_op_nop
+GEN32(gen_op_load_T0_ir, gen_op_load_T0_ir);
+GEN32(gen_op_load_T1_ir, gen_op_load_T1_ir);
+GEN32(gen_op_load_T2_ir, gen_op_load_T2_ir);
+GEN32(gen_op_store_T0_ir, gen_op_store_T0_ir);
+GEN32(gen_op_store_T1_ir, gen_op_store_T1_ir);
+GEN32(gen_op_store_T2_ir, gen_op_store_T2_ir);
+GEN32(gen_op_cmov_ir, gen_op_cmov_ir);
+
+static inline void gen_load_ir (DisasContext *ctx, int irn, int Tn)
+{
+ switch (Tn) {
+ case 0:
+ gen_op_load_T0_ir(irn);
+ break;
+ case 1:
+ gen_op_load_T1_ir(irn);
+ break;
+ case 2:
+ gen_op_load_T2_ir(irn);
+ break;
+ }
+}
+
+static inline void gen_store_ir (DisasContext *ctx, int irn, int Tn)
+{
+ switch (Tn) {
+ case 0:
+ gen_op_store_T0_ir(irn);
+ break;
+ case 1:
+ gen_op_store_T1_ir(irn);
+ break;
+ case 2:
+ gen_op_store_T2_ir(irn);
+ break;
+ }
+}
+
+/* FIR moves */
+/* Special hacks for fir31 */
+#define gen_op_load_FT0_fir31 gen_op_reset_FT0
+#define gen_op_load_FT1_fir31 gen_op_reset_FT1
+#define gen_op_load_FT2_fir31 gen_op_reset_FT2
+#define gen_op_store_FT0_fir31 gen_op_nop
+#define gen_op_store_FT1_fir31 gen_op_nop
+#define gen_op_store_FT2_fir31 gen_op_nop
+#define gen_op_cmov_fir31 gen_op_nop
+GEN32(gen_op_load_FT0_fir, gen_op_load_FT0_fir);
+GEN32(gen_op_load_FT1_fir, gen_op_load_FT1_fir);
+GEN32(gen_op_load_FT2_fir, gen_op_load_FT2_fir);
+GEN32(gen_op_store_FT0_fir, gen_op_store_FT0_fir);
+GEN32(gen_op_store_FT1_fir, gen_op_store_FT1_fir);
+GEN32(gen_op_store_FT2_fir, gen_op_store_FT2_fir);
+GEN32(gen_op_cmov_fir, gen_op_cmov_fir);
+
+static inline void gen_load_fir (DisasContext *ctx, int firn, int Tn)
+{
+ switch (Tn) {
+ case 0:
+ gen_op_load_FT0_fir(firn);
+ break;
+ case 1:
+ gen_op_load_FT1_fir(firn);
+ break;
+ case 2:
+ gen_op_load_FT2_fir(firn);
+ break;
+ }
+}
+
+static inline void gen_store_fir (DisasContext *ctx, int firn, int Tn)
+{
+ switch (Tn) {
+ case 0:
+ gen_op_store_FT0_fir(firn);
+ break;
+ case 1:
+ gen_op_store_FT1_fir(firn);
+ break;
+ case 2:
+ gen_op_store_FT2_fir(firn);
+ break;
+ }
+}
+
+/* Memory moves */
+#if defined(CONFIG_USER_ONLY)
+#define OP_LD_TABLE(width) \
+static GenOpFunc *gen_op_ld##width[] = { \
+ &gen_op_ld##width##_raw, \
+}
+#define OP_ST_TABLE(width) \
+static GenOpFunc *gen_op_st##width[] = { \
+ &gen_op_st##width##_raw, \
+}
+#else
+#define OP_LD_TABLE(width) \
+static GenOpFunc *gen_op_ld##width[] = { \
+ &gen_op_ld##width##_kernel, \
+ &gen_op_ld##width##_user, /* executive */ \
+ &gen_op_ld##width##_data, /* supervisor */ \
+ &gen_op_ld##width##_data, /* user */ \
+}
+#define OP_ST_TABLE(width) \
+static GenOpFunc *gen_op_st##width[] = { \
+ &gen_op_st##width##_kernel, \
+ &gen_op_st##width##_user, /* executive */ \
+ &gen_op_st##width##_data, /* supervisor */ \
+ &gen_op_st##width##_data, /* user */ \
+}
+#endif
+
+#define GEN_LD(width) \
+OP_LD_TABLE(width); \
+static void gen_ld##width (DisasContext *ctx) \
+{ \
+ (*gen_op_ld##width[ctx->mem_idx])(); \
+}
+
+#define GEN_ST(width) \
+OP_ST_TABLE(width); \
+static void gen_st##width (DisasContext *ctx) \
+{ \
+ (*gen_op_st##width[ctx->mem_idx])(); \
+}
+
+GEN_LD(bu);
+GEN_ST(b);
+GEN_LD(wu);
+GEN_ST(w);
+GEN_LD(l);
+GEN_ST(l);
+GEN_LD(q);
+GEN_ST(q);
+GEN_LD(q_u);
+GEN_ST(q_u);
+GEN_LD(l_l);
+GEN_ST(l_c);
+GEN_LD(q_l);
+GEN_ST(q_c);
+
+GEN_LD(f);
+GEN_ST(f);
+GEN_LD(g);
+GEN_ST(g);
+GEN_LD(s);
+GEN_ST(s);
+GEN_LD(t);
+GEN_ST(t);
+
+#if defined(__i386__) || defined(__x86_64__)
+static inline void gen_op_set_s16_T0 (int16_t imm)
+{
+ gen_op_set_s32_T0((int32_t)imm);
+}
+
+static inline void gen_op_set_s16_T1 (int16_t imm)
+{
+ gen_op_set_s32_T1((int32_t)imm);
+}
+
+static inline void gen_op_set_u16_T0 (uint16_t imm)
+{
+ gen_op_set_s32_T0((uint32_t)imm);
+}
+
+static inline void gen_op_set_u16_T1 (uint16_t imm)
+{
+ gen_op_set_s32_T1((uint32_t)imm);
+}
+#endif
+
+static inline void gen_set_sT0 (DisasContext *ctx, int64_t imm)
+{
+ int32_t imm32;
+ int16_t imm16;
+
+ imm32 = imm;
+ if (imm32 == imm) {
+ imm16 = imm;
+ if (imm16 == imm) {
+ if (imm == 0) {
+ gen_op_reset_T0();
+ } else {
+ gen_op_set_s16_T0(imm16);
+ }
+ } else {
+ gen_op_set_s32_T0(imm32);
+ }
+ } else {
+#if 0 // Qemu does not know how to do this...
+ gen_op_set_64_T0(imm);
+#else
+ gen_op_set_64_T0(imm >> 32, imm);
+#endif
+ }
+}
+
+static inline void gen_set_sT1 (DisasContext *ctx, int64_t imm)
+{
+ int32_t imm32;
+ int16_t imm16;
+
+ imm32 = imm;
+ if (imm32 == imm) {
+ imm16 = imm;
+ if (imm16 == imm) {
+ if (imm == 0) {
+ gen_op_reset_T1();
+ } else {
+ gen_op_set_s16_T1(imm16);
+ }
+ } else {
+ gen_op_set_s32_T1(imm32);
+ }
+ } else {
+#if 0 // Qemu does not know how to do this...
+ gen_op_set_64_T1(imm);
+#else
+ gen_op_set_64_T1(imm >> 32, imm);
+#endif
+ }
+}
+
+static inline void gen_set_uT0 (DisasContext *ctx, uint64_t imm)
+{
+ if (!(imm >> 32)) {
+ if ((!imm >> 16)) {
+ if (imm == 0)
+ gen_op_reset_T0();
+ else
+ gen_op_set_u16_T0(imm);
+ } else {
+ gen_op_set_u32_T0(imm);
+ }
+ } else {
+#if 0 // Qemu does not know how to do this...
+ gen_op_set_64_T0(imm);
+#else
+ gen_op_set_64_T0(imm >> 32, imm);
+#endif
+ }
+}
+
+static inline void gen_set_uT1 (DisasContext *ctx, uint64_t imm)
+{
+ if (!(imm >> 32)) {
+ if ((!imm >> 16)) {
+ if (imm == 0)
+ gen_op_reset_T1();
+ else
+ gen_op_set_u16_T1(imm);
+ } else {
+ gen_op_set_u32_T1(imm);
+ }
+ } else {
+#if 0 // Qemu does not know how to do this...
+ gen_op_set_64_T1(imm);
+#else
+ gen_op_set_64_T1(imm >> 32, imm);
+#endif
+ }
+}
+
+static inline void gen_update_pc (DisasContext *ctx)
+{
+ if (!(ctx->pc >> 32)) {
+ gen_op_update_pc32(ctx->pc);
+ } else {
+#if 0 // Qemu does not know how to do this...
+ gen_op_update_pc(ctx->pc);
+#else
+ gen_op_update_pc(ctx->pc >> 32, ctx->pc);
+#endif
+ }
+}
+
+static inline void _gen_op_bcond (DisasContext *ctx)
+{
+#if 0 // Qemu does not know how to do this...
+ gen_op_bcond(ctx->pc);
+#else
+ gen_op_bcond(ctx->pc >> 32, ctx->pc);
+#endif
+}
+
+static inline void gen_excp (DisasContext *ctx, int exception, int error_code)
+{
+ gen_update_pc(ctx);
+ gen_op_excp(exception, error_code);
+}
+
+static inline void gen_invalid (DisasContext *ctx)
+{
+ gen_excp(ctx, EXCP_OPCDEC, 0);
+}
+
+static void gen_load_mem (DisasContext *ctx,
+ void (*gen_load_op)(DisasContext *ctx),
+ int ra, int rb, int32_t disp16, int clear)
+{
+ if (ra == 31 && disp16 == 0) {
+ /* UNOP */
+ gen_op_nop();
+ } else {
+ gen_load_ir(ctx, rb, 0);
+ if (disp16 != 0) {
+ gen_set_sT1(ctx, disp16);
+ gen_op_addq();
+ }
+ if (clear)
+ gen_op_n7();
+ (*gen_load_op)(ctx);
+ gen_store_ir(ctx, ra, 1);
+ }
+}
+
+static void gen_store_mem (DisasContext *ctx,
+ void (*gen_store_op)(DisasContext *ctx),
+ int ra, int rb, int32_t disp16, int clear)
+{
+ gen_load_ir(ctx, rb, 0);
+ if (disp16 != 0) {
+ gen_set_sT1(ctx, disp16);
+ gen_op_addq();
+ }
+ if (clear)
+ gen_op_n7();
+ gen_load_ir(ctx, ra, 1);
+ (*gen_store_op)(ctx);
+}
+
+static void gen_load_fmem (DisasContext *ctx,
+ void (*gen_load_fop)(DisasContext *ctx),
+ int ra, int rb, int32_t disp16)
+{
+ gen_load_ir(ctx, rb, 0);
+ if (disp16 != 0) {
+ gen_set_sT1(ctx, disp16);
+ gen_op_addq();
+ }
+ (*gen_load_fop)(ctx);
+ gen_store_fir(ctx, ra, 1);
+}
+
+static void gen_store_fmem (DisasContext *ctx,
+ void (*gen_store_fop)(DisasContext *ctx),
+ int ra, int rb, int32_t disp16)
+{
+ gen_load_ir(ctx, rb, 0);
+ if (disp16 != 0) {
+ gen_set_sT1(ctx, disp16);
+ gen_op_addq();
+ }
+ gen_load_fir(ctx, ra, 1);
+ (*gen_store_fop)(ctx);
+}
+
+static void gen_bcond (DisasContext *ctx, void (*gen_test_op)(void),
+ int ra, int32_t disp16)
+{
+ if (disp16 != 0) {
+ gen_set_uT0(ctx, ctx->pc);
+ gen_set_sT1(ctx, disp16 << 2);
+ gen_op_addq1();
+ } else {
+ gen_set_uT1(ctx, ctx->pc);
+ }
+ gen_load_ir(ctx, ra, 0);
+ (*gen_test_op)();
+ _gen_op_bcond(ctx);
+}
+
+static void gen_fbcond (DisasContext *ctx, void (*gen_test_op)(void),
+ int ra, int32_t disp16)
+{
+ if (disp16 != 0) {
+ gen_set_uT0(ctx, ctx->pc);
+ gen_set_sT1(ctx, disp16 << 2);
+ gen_op_addq1();
+ } else {
+ gen_set_uT1(ctx, ctx->pc);
+ }
+ gen_load_fir(ctx, ra, 0);
+ (*gen_test_op)();
+ _gen_op_bcond(ctx);
+}
+
+static void gen_arith2 (DisasContext *ctx, void (*gen_arith_op)(void),
+ int rb, int rc, int islit, int8_t lit)
+{
+ if (islit)
+ gen_set_sT0(ctx, lit);
+ else
+ gen_load_ir(ctx, rb, 0);
+ (*gen_arith_op)();
+ gen_store_ir(ctx, rc, 0);
+}
+
+static void gen_arith3 (DisasContext *ctx, void (*gen_arith_op)(void),
+ int ra, int rb, int rc, int islit, int8_t lit)
+{
+ gen_load_ir(ctx, ra, 0);
+ if (islit)
+ gen_set_sT1(ctx, lit);
+ else
+ gen_load_ir(ctx, rb, 1);
+ (*gen_arith_op)();
+ gen_store_ir(ctx, rc, 0);
+}
+
+static void gen_cmov (DisasContext *ctx, void (*gen_test_op)(void),
+ int ra, int rb, int rc, int islit, int8_t lit)
+{
+ gen_load_ir(ctx, ra, 1);
+ if (islit)
+ gen_set_sT0(ctx, lit);
+ else
+ gen_load_ir(ctx, rb, 0);
+ (*gen_test_op)();
+ gen_op_cmov_ir(rc);
+}
+
+static void gen_farith2 (DisasContext *ctx, void (*gen_arith_fop)(void),
+ int rb, int rc)
+{
+ gen_load_fir(ctx, rb, 0);
+ (*gen_arith_fop)();
+ gen_store_fir(ctx, rc, 0);
+}
+
+static void gen_farith3 (DisasContext *ctx, void (*gen_arith_fop)(void),
+ int ra, int rb, int rc)
+{
+ gen_load_fir(ctx, ra, 0);
+ gen_load_fir(ctx, rb, 1);
+ (*gen_arith_fop)();
+ gen_store_fir(ctx, rc, 0);
+}
+
+static void gen_fcmov (DisasContext *ctx, void (*gen_test_fop)(void),
+ int ra, int rb, int rc)
+{
+ gen_load_fir(ctx, ra, 0);
+ gen_load_fir(ctx, rb, 1);
+ (*gen_test_fop)();
+ gen_op_cmov_fir(rc);
+}
+
+static void gen_fti (DisasContext *ctx, void (*gen_move_fop)(void),
+ int ra, int rc)
+{
+ gen_load_fir(ctx, rc, 0);
+ (*gen_move_fop)();
+ gen_store_ir(ctx, ra, 0);
+}
+
+static void gen_itf (DisasContext *ctx, void (*gen_move_fop)(void),
+ int ra, int rc)
+{
+ gen_load_ir(ctx, ra, 0);
+ (*gen_move_fop)();
+ gen_store_fir(ctx, rc, 0);
+}
+
+static void gen_s4addl (void)
+{
+ gen_op_s4();
+ gen_op_addl();
+}
+
+static void gen_s4subl (void)
+{
+ gen_op_s4();
+ gen_op_subl();
+}
+
+static void gen_s8addl (void)
+{
+ gen_op_s8();
+ gen_op_addl();
+}
+
+static void gen_s8subl (void)
+{
+ gen_op_s8();
+ gen_op_subl();
+}
+
+static void gen_s4addq (void)
+{
+ gen_op_s4();
+ gen_op_addq();
+}
+
+static void gen_s4subq (void)
+{
+ gen_op_s4();
+ gen_op_subq();
+}
+
+static void gen_s8addq (void)
+{
+ gen_op_s8();
+ gen_op_addq();
+}
+
+static void gen_s8subq (void)
+{
+ gen_op_s8();
+ gen_op_subq();
+}
+
+static void gen_amask (void)
+{
+ gen_op_load_amask();
+ gen_op_bic();
+}
+
+static int translate_one (DisasContext *ctx, uint32_t insn)
+{
+ uint32_t palcode;
+ int32_t disp21, disp16, disp12;
+ uint16_t fn11, fn16;
+ uint8_t opc, ra, rb, rc, sbz, fpfn, fn7, fn2, islit;
+ int8_t lit;
+ int ret;
+
+ /* Decode all instruction fields */
+ opc = insn >> 26;
+ ra = (insn >> 21) & 0x1F;
+ rb = (insn >> 16) & 0x1F;
+ rc = insn & 0x1F;
+ sbz = (insn >> 13) & 0x07;
+ islit = (insn >> 12) & 1;
+ lit = (insn >> 13) & 0xFF;
+ palcode = insn & 0x03FFFFFF;
+ disp21 = ((int32_t)((insn & 0x001FFFFF) << 11)) >> 11;
+ disp16 = (int16_t)(insn & 0x0000FFFF);
+ disp12 = (int32_t)((insn & 0x00000FFF) << 20) >> 20;
+ fn16 = insn & 0x0000FFFF;
+ fn11 = (insn >> 5) & 0x000007FF;
+ fpfn = fn11 & 0x3F;
+ fn7 = (insn >> 5) & 0x0000007F;
+ fn2 = (insn >> 5) & 0x00000003;
+ ret = 0;
+#if defined ALPHA_DEBUG_DISAS
+ if (logfile != NULL) {
+ fprintf(logfile, "opc %02x ra %d rb %d rc %d disp16 %04x\n",
+ opc, ra, rb, rc, disp16);
+ }
+#endif
+ switch (opc) {
+ case 0x00:
+ /* CALL_PAL */
+ if (palcode >= 0x80 && palcode < 0xC0) {
+ /* Unprivileged PAL call */
+ gen_excp(ctx, EXCP_CALL_PAL + ((palcode & 0x1F) << 6), 0);
+#if !defined (CONFIG_USER_ONLY)
+ } else if (palcode < 0x40) {
+ /* Privileged PAL code */
+ if (ctx->mem_idx & 1)
+ goto invalid_opc;
+ else
+ gen_excp(ctx, EXCP_CALL_PALP + ((palcode & 0x1F) << 6), 0);
+#endif
+ } else {
+ /* Invalid PAL call */
+ goto invalid_opc;
+ }
+ ret = 3;
+ break;
+ case 0x01:
+ /* OPC01 */
+ goto invalid_opc;
+ case 0x02:
+ /* OPC02 */
+ goto invalid_opc;
+ case 0x03:
+ /* OPC03 */
+ goto invalid_opc;
+ case 0x04:
+ /* OPC04 */
+ goto invalid_opc;
+ case 0x05:
+ /* OPC05 */
+ goto invalid_opc;
+ case 0x06:
+ /* OPC06 */
+ goto invalid_opc;
+ case 0x07:
+ /* OPC07 */
+ goto invalid_opc;
+ case 0x08:
+ /* LDA */
+ gen_load_ir(ctx, rb, 0);
+ gen_set_sT1(ctx, disp16);
+ gen_op_addq();
+ gen_store_ir(ctx, ra, 0);
+ break;
+ case 0x09:
+ /* LDAH */
+ gen_load_ir(ctx, rb, 0);
+ gen_set_sT1(ctx, disp16 << 16);
+ gen_op_addq();
+ gen_store_ir(ctx, ra, 0);
+ break;
+ case 0x0A:
+ /* LDBU */
+ if (!(ctx->amask & AMASK_BWX))
+ goto invalid_opc;
+ gen_load_mem(ctx, &gen_ldbu, ra, rb, disp16, 0);
+ break;
+ case 0x0B:
+ /* LDQ_U */
+ gen_load_mem(ctx, &gen_ldq_u, ra, rb, disp16, 1);
+ break;
+ case 0x0C:
+ /* LDWU */
+ if (!(ctx->amask & AMASK_BWX))
+ goto invalid_opc;
+ gen_load_mem(ctx, &gen_ldwu, ra, rb, disp16, 0);
+ break;
+ case 0x0D:
+ /* STW */
+ if (!(ctx->amask & AMASK_BWX))
+ goto invalid_opc;
+ gen_store_mem(ctx, &gen_stw, ra, rb, disp16, 0);
+ break;
+ case 0x0E:
+ /* STB */
+ if (!(ctx->amask & AMASK_BWX))
+ goto invalid_opc;
+ gen_store_mem(ctx, &gen_stb, ra, rb, disp16, 0);
+ break;
+ case 0x0F:
+ /* STQ_U */
+ gen_store_mem(ctx, &gen_stq_u, ra, rb, disp16, 1);
+ break;
+ case 0x10:
+ switch (fn7) {
+ case 0x00:
+ /* ADDL */
+ gen_arith3(ctx, &gen_op_addl, ra, rb, rc, islit, lit);
+ break;
+ case 0x02:
+ /* S4ADDL */
+ gen_arith3(ctx, &gen_s4addl, ra, rb, rc, islit, lit);
+ break;
+ case 0x09:
+ /* SUBL */
+ gen_arith3(ctx, &gen_op_subl, ra, rb, rc, islit, lit);
+ break;
+ case 0x0B:
+ /* S4SUBL */
+ gen_arith3(ctx, &gen_s4subl, ra, rb, rc, islit, lit);
+ break;
+ case 0x0F:
+ /* CMPBGE */
+ gen_arith3(ctx, &gen_op_cmpbge, ra, rb, rc, islit, lit);
+ break;
+ case 0x12:
+ /* S8ADDL */
+ gen_arith3(ctx, &gen_s8addl, ra, rb, rc, islit, lit);
+ break;
+ case 0x1B:
+ /* S8SUBL */
+ gen_arith3(ctx, &gen_s8subl, ra, rb, rc, islit, lit);
+ break;
+ case 0x1D:
+ /* CMPULT */
+ gen_arith3(ctx, &gen_op_cmpult, ra, rb, rc, islit, lit);
+ break;
+ case 0x20:
+ /* ADDQ */
+ gen_arith3(ctx, &gen_op_addq, ra, rb, rc, islit, lit);
+ break;
+ case 0x22:
+ /* S4ADDQ */
+ gen_arith3(ctx, &gen_s4addq, ra, rb, rc, islit, lit);
+ break;
+ case 0x29:
+ /* SUBQ */
+ gen_arith3(ctx, &gen_op_subq, ra, rb, rc, islit, lit);
+ break;
+ case 0x2B:
+ /* S4SUBQ */
+ gen_arith3(ctx, &gen_s4subq, ra, rb, rc, islit, lit);
+ break;
+ case 0x2D:
+ /* CMPEQ */
+ gen_arith3(ctx, &gen_op_cmpeq, ra, rb, rc, islit, lit);
+ break;
+ case 0x32:
+ /* S8ADDQ */
+ gen_arith3(ctx, &gen_s8addq, ra, rb, rc, islit, lit);
+ break;
+ case 0x3B:
+ /* S8SUBQ */
+ gen_arith3(ctx, &gen_s8subq, ra, rb, rc, islit, lit);
+ break;
+ case 0x3D:
+ /* CMPULE */
+ gen_arith3(ctx, &gen_op_cmpule, ra, rb, rc, islit, lit);
+ break;
+ case 0x40:
+ /* ADDL/V */
+ gen_arith3(ctx, &gen_op_addlv, ra, rb, rc, islit, lit);
+ break;
+ case 0x49:
+ /* SUBL/V */
+ gen_arith3(ctx, &gen_op_sublv, ra, rb, rc, islit, lit);
+ break;
+ case 0x4D:
+ /* CMPLT */
+ gen_arith3(ctx, &gen_op_cmplt, ra, rb, rc, islit, lit);
+ break;
+ case 0x60:
+ /* ADDQ/V */
+ gen_arith3(ctx, &gen_op_addqv, ra, rb, rc, islit, lit);
+ break;
+ case 0x69:
+ /* SUBQ/V */
+ gen_arith3(ctx, &gen_op_subqv, ra, rb, rc, islit, lit);
+ break;
+ case 0x6D:
+ /* CMPLE */
+ gen_arith3(ctx, &gen_op_cmple, ra, rb, rc, islit, lit);
+ break;
+ default:
+ goto invalid_opc;
+ }
+ break;
+ case 0x11:
+ switch (fn7) {
+ case 0x00:
+ /* AND */
+ gen_arith3(ctx, &gen_op_and, ra, rb, rc, islit, lit);
+ break;
+ case 0x08:
+ /* BIC */
+ gen_arith3(ctx, &gen_op_bic, ra, rb, rc, islit, lit);
+ break;
+ case 0x14:
+ /* CMOVLBS */
+ gen_cmov(ctx, &gen_op_cmplbs, ra, rb, rc, islit, lit);
+ break;
+ case 0x16:
+ /* CMOVLBC */
+ gen_cmov(ctx, &gen_op_cmplbc, ra, rb, rc, islit, lit);
+ break;
+ case 0x20:
+ /* BIS */
+ if (ra == rb || ra == 31 || rb == 31) {
+ if (ra == 31 && rc == 31) {
+ /* NOP */
+ gen_op_nop();
+ } else {
+ /* MOV */
+ gen_load_ir(ctx, rb, 0);
+ gen_store_ir(ctx, rc, 0);
+ }
+ } else {
+ gen_arith3(ctx, &gen_op_bis, ra, rb, rc, islit, lit);
+ }
+ break;
+ case 0x24:
+ /* CMOVEQ */
+ gen_cmov(ctx, &gen_op_cmpeqz, ra, rb, rc, islit, lit);
+ break;
+ case 0x26:
+ /* CMOVNE */
+ gen_cmov(ctx, &gen_op_cmpnez, ra, rb, rc, islit, lit);
+ break;
+ case 0x28:
+ /* ORNOT */
+ gen_arith3(ctx, &gen_op_ornot, ra, rb, rc, islit, lit);
+ break;
+ case 0x40:
+ /* XOR */
+ gen_arith3(ctx, &gen_op_xor, ra, rb, rc, islit, lit);
+ break;
+ case 0x44:
+ /* CMOVLT */
+ gen_cmov(ctx, &gen_op_cmpltz, ra, rb, rc, islit, lit);
+ break;
+ case 0x46:
+ /* CMOVGE */
+ gen_cmov(ctx, &gen_op_cmpgez, ra, rb, rc, islit, lit);
+ break;
+ case 0x48:
+ /* EQV */
+ gen_arith3(ctx, &gen_op_eqv, ra, rb, rc, islit, lit);
+ break;
+ case 0x61:
+ /* AMASK */
+ gen_arith2(ctx, &gen_amask, rb, rc, islit, lit);
+ break;
+ case 0x64:
+ /* CMOVLE */
+ gen_cmov(ctx, &gen_op_cmplez, ra, rb, rc, islit, lit);
+ break;
+ case 0x66:
+ /* CMOVGT */
+ gen_cmov(ctx, &gen_op_cmpgtz, ra, rb, rc, islit, lit);
+ break;
+ case 0x6C:
+ /* IMPLVER */
+ gen_op_load_implver();
+ gen_store_ir(ctx, rc, 0);
+ break;
+ default:
+ goto invalid_opc;
+ }
+ break;
+ case 0x12:
+ switch (fn7) {
+ case 0x02:
+ /* MSKBL */
+ gen_arith3(ctx, &gen_op_mskbl, ra, rb, rc, islit, lit);
+ break;
+ case 0x06:
+ /* EXTBL */
+ gen_arith3(ctx, &gen_op_extbl, ra, rb, rc, islit, lit);
+ break;
+ case 0x0B:
+ /* INSBL */
+ gen_arith3(ctx, &gen_op_insbl, ra, rb, rc, islit, lit);
+ break;
+ case 0x12:
+ /* MSKWL */
+ gen_arith3(ctx, &gen_op_mskwl, ra, rb, rc, islit, lit);
+ break;
+ case 0x16:
+ /* EXTWL */
+ gen_arith3(ctx, &gen_op_extwl, ra, rb, rc, islit, lit);
+ break;
+ case 0x1B:
+ /* INSWL */
+ gen_arith3(ctx, &gen_op_inswl, ra, rb, rc, islit, lit);
+ break;
+ case 0x22:
+ /* MSKLL */
+ gen_arith3(ctx, &gen_op_mskll, ra, rb, rc, islit, lit);
+ break;
+ case 0x26:
+ /* EXTLL */
+ gen_arith3(ctx, &gen_op_extll, ra, rb, rc, islit, lit);
+ break;
+ case 0x2B:
+ /* INSLL */
+ gen_arith3(ctx, &gen_op_insll, ra, rb, rc, islit, lit);
+ break;
+ case 0x30:
+ /* ZAP */
+ gen_arith3(ctx, &gen_op_zap, ra, rb, rc, islit, lit);
+ break;
+ case 0x31:
+ /* ZAPNOT */
+ gen_arith3(ctx, &gen_op_zapnot, ra, rb, rc, islit, lit);
+ break;
+ case 0x32:
+ /* MSKQL */
+ gen_arith3(ctx, &gen_op_mskql, ra, rb, rc, islit, lit);
+ break;
+ case 0x34:
+ /* SRL */
+ gen_arith3(ctx, &gen_op_srl, ra, rb, rc, islit, lit);
+ break;
+ case 0x36:
+ /* EXTQL */
+ gen_arith3(ctx, &gen_op_extql, ra, rb, rc, islit, lit);
+ break;
+ case 0x39:
+ /* SLL */
+ gen_arith3(ctx, &gen_op_sll, ra, rb, rc, islit, lit);
+ break;
+ case 0x3B:
+ /* INSQL */
+ gen_arith3(ctx, &gen_op_insql, ra, rb, rc, islit, lit);
+ break;
+ case 0x3C:
+ /* SRA */
+ gen_arith3(ctx, &gen_op_sra, ra, rb, rc, islit, lit);
+ break;
+ case 0x52:
+ /* MSKWH */
+ gen_arith3(ctx, &gen_op_mskwh, ra, rb, rc, islit, lit);
+ break;
+ case 0x57:
+ /* INSWH */
+ gen_arith3(ctx, &gen_op_inswh, ra, rb, rc, islit, lit);
+ break;
+ case 0x5A:
+ /* EXTWH */
+ gen_arith3(ctx, &gen_op_extwh, ra, rb, rc, islit, lit);
+ break;
+ case 0x62:
+ /* MSKLH */
+ gen_arith3(ctx, &gen_op_msklh, ra, rb, rc, islit, lit);
+ break;
+ case 0x67:
+ /* INSLH */
+ gen_arith3(ctx, &gen_op_inslh, ra, rb, rc, islit, lit);
+ break;
+ case 0x6A:
+ /* EXTLH */
+ gen_arith3(ctx, &gen_op_extlh, ra, rb, rc, islit, lit);
+ break;
+ case 0x72:
+ /* MSKQH */
+ gen_arith3(ctx, &gen_op_mskqh, ra, rb, rc, islit, lit);
+ break;
+ case 0x77:
+ /* INSQH */
+ gen_arith3(ctx, &gen_op_insqh, ra, rb, rc, islit, lit);
+ break;
+ case 0x7A:
+ /* EXTQH */
+ gen_arith3(ctx, &gen_op_extqh, ra, rb, rc, islit, lit);
+ break;
+ default:
+ goto invalid_opc;
+ }
+ break;
+ case 0x13:
+ switch (fn7) {
+ case 0x00:
+ /* MULL */
+ gen_arith3(ctx, &gen_op_mull, ra, rb, rc, islit, lit);
+ break;
+ case 0x20:
+ /* MULQ */
+ gen_arith3(ctx, &gen_op_mulq, ra, rb, rc, islit, lit);
+ break;
+ case 0x30:
+ /* UMULH */
+ gen_arith3(ctx, &gen_op_umulh, ra, rb, rc, islit, lit);
+ break;
+ case 0x40:
+ /* MULL/V */
+ gen_arith3(ctx, &gen_op_mullv, ra, rb, rc, islit, lit);
+ break;
+ case 0x60:
+ /* MULQ/V */
+ gen_arith3(ctx, &gen_op_mulqv, ra, rb, rc, islit, lit);
+ break;
+ default:
+ goto invalid_opc;
+ }
+ break;
+ case 0x14:
+ switch (fpfn) { /* f11 & 0x3F */
+ case 0x04:
+ /* ITOFS */
+ if (!(ctx->amask & AMASK_FIX))
+ goto invalid_opc;
+ gen_itf(ctx, &gen_op_itofs, ra, rc);
+ break;
+ case 0x0A:
+ /* SQRTF */
+ if (!(ctx->amask & AMASK_FIX))
+ goto invalid_opc;
+ gen_farith2(ctx, &gen_op_sqrtf, rb, rc);
+ break;
+ case 0x0B:
+ /* SQRTS */
+ if (!(ctx->amask & AMASK_FIX))
+ goto invalid_opc;
+ gen_farith2(ctx, &gen_op_sqrts, rb, rc);
+ break;
+ case 0x14:
+ /* ITOFF */
+ if (!(ctx->amask & AMASK_FIX))
+ goto invalid_opc;
+#if 0 // TODO
+ gen_itf(ctx, &gen_op_itoff, ra, rc);
+#else
+ goto invalid_opc;
+#endif
+ break;
+ case 0x24:
+ /* ITOFT */
+ if (!(ctx->amask & AMASK_FIX))
+ goto invalid_opc;
+ gen_itf(ctx, &gen_op_itoft, ra, rc);
+ break;
+ case 0x2A:
+ /* SQRTG */
+ if (!(ctx->amask & AMASK_FIX))
+ goto invalid_opc;
+ gen_farith2(ctx, &gen_op_sqrtg, rb, rc);
+ break;
+ case 0x02B:
+ /* SQRTT */
+ if (!(ctx->amask & AMASK_FIX))
+ goto invalid_opc;
+ gen_farith2(ctx, &gen_op_sqrtt, rb, rc);
+ break;
+ default:
+ goto invalid_opc;
+ }
+ break;
+ case 0x15:
+ /* VAX floating point */
+ /* XXX: rounding mode and trap are ignored (!) */
+ switch (fpfn) { /* f11 & 0x3F */
+ case 0x00:
+ /* ADDF */
+ gen_farith3(ctx, &gen_op_addf, ra, rb, rc);
+ break;
+ case 0x01:
+ /* SUBF */
+ gen_farith3(ctx, &gen_op_subf, ra, rb, rc);
+ break;
+ case 0x02:
+ /* MULF */
+ gen_farith3(ctx, &gen_op_mulf, ra, rb, rc);
+ break;
+ case 0x03:
+ /* DIVF */
+ gen_farith3(ctx, &gen_op_divf, ra, rb, rc);
+ break;
+ case 0x1E:
+ /* CVTDG */
+#if 0 // TODO
+ gen_farith2(ctx, &gen_op_cvtdg, rb, rc);
+#else
+ goto invalid_opc;
+#endif
+ break;
+ case 0x20:
+ /* ADDG */
+ gen_farith3(ctx, &gen_op_addg, ra, rb, rc);
+ break;
+ case 0x21:
+ /* SUBG */
+ gen_farith3(ctx, &gen_op_subg, ra, rb, rc);
+ break;
+ case 0x22:
+ /* MULG */
+ gen_farith3(ctx, &gen_op_mulg, ra, rb, rc);
+ break;
+ case 0x23:
+ /* DIVG */
+ gen_farith3(ctx, &gen_op_divg, ra, rb, rc);
+ break;
+ case 0x25:
+ /* CMPGEQ */
+ gen_farith3(ctx, &gen_op_cmpgeq, ra, rb, rc);
+ break;
+ case 0x26:
+ /* CMPGLT */
+ gen_farith3(ctx, &gen_op_cmpglt, ra, rb, rc);
+ break;
+ case 0x27:
+ /* CMPGLE */
+ gen_farith3(ctx, &gen_op_cmpgle, ra, rb, rc);
+ break;
+ case 0x2C:
+ /* CVTGF */
+ gen_farith2(ctx, &gen_op_cvtgf, rb, rc);
+ break;
+ case 0x2D:
+ /* CVTGD */
+#if 0 // TODO
+ gen_farith2(ctx, &gen_op_cvtgd, rb, rc);
+#else
+ goto invalid_opc;
+#endif
+ break;
+ case 0x2F:
+ /* CVTGQ */
+ gen_farith2(ctx, &gen_op_cvtgq, rb, rc);
+ break;
+ case 0x3C:
+ /* CVTQF */
+ gen_farith2(ctx, &gen_op_cvtqf, rb, rc);
+ break;
+ case 0x3E:
+ /* CVTQG */
+ gen_farith2(ctx, &gen_op_cvtqg, rb, rc);
+ break;
+ default:
+ goto invalid_opc;
+ }
+ break;
+ case 0x16:
+ /* IEEE floating-point */
+ /* XXX: rounding mode and traps are ignored (!) */
+ switch (fpfn) { /* f11 & 0x3F */
+ case 0x00:
+ /* ADDS */
+ gen_farith3(ctx, &gen_op_adds, ra, rb, rc);
+ break;
+ case 0x01:
+ /* SUBS */
+ gen_farith3(ctx, &gen_op_subs, ra, rb, rc);
+ break;
+ case 0x02:
+ /* MULS */
+ gen_farith3(ctx, &gen_op_muls, ra, rb, rc);
+ break;
+ case 0x03:
+ /* DIVS */
+ gen_farith3(ctx, &gen_op_divs, ra, rb, rc);
+ break;
+ case 0x20:
+ /* ADDT */
+ gen_farith3(ctx, &gen_op_addt, ra, rb, rc);
+ break;
+ case 0x21:
+ /* SUBT */
+ gen_farith3(ctx, &gen_op_subt, ra, rb, rc);
+ break;
+ case 0x22:
+ /* MULT */
+ gen_farith3(ctx, &gen_op_mult, ra, rb, rc);
+ break;
+ case 0x23:
+ /* DIVT */
+ gen_farith3(ctx, &gen_op_divt, ra, rb, rc);
+ break;
+ case 0x24:
+ /* CMPTUN */
+ gen_farith3(ctx, &gen_op_cmptun, ra, rb, rc);
+ break;
+ case 0x25:
+ /* CMPTEQ */
+ gen_farith3(ctx, &gen_op_cmpteq, ra, rb, rc);
+ break;
+ case 0x26:
+ /* CMPTLT */
+ gen_farith3(ctx, &gen_op_cmptlt, ra, rb, rc);
+ break;
+ case 0x27:
+ /* CMPTLE */
+ gen_farith3(ctx, &gen_op_cmptle, ra, rb, rc);
+ break;
+ case 0x2C:
+ /* XXX: incorrect */
+ if (fn11 == 0x2AC) {
+ /* CVTST */
+ gen_farith2(ctx, &gen_op_cvtst, rb, rc);
+ } else {
+ /* CVTTS */
+ gen_farith2(ctx, &gen_op_cvtts, rb, rc);
+ }
+ break;
+ case 0x2F:
+ /* CVTTQ */
+ gen_farith2(ctx, &gen_op_cvttq, rb, rc);
+ break;
+ case 0x3C:
+ /* CVTQS */
+ gen_farith2(ctx, &gen_op_cvtqs, rb, rc);
+ break;
+ case 0x3E:
+ /* CVTQT */
+ gen_farith2(ctx, &gen_op_cvtqt, rb, rc);
+ break;
+ default:
+ goto invalid_opc;
+ }
+ break;
+ case 0x17:
+ switch (fn11) {
+ case 0x010:
+ /* CVTLQ */
+ gen_farith2(ctx, &gen_op_cvtlq, rb, rc);
+ break;
+ case 0x020:
+ /* CPYS */
+ if (ra == rb) {
+ if (ra == 31 && rc == 31) {
+ /* FNOP */
+ gen_op_nop();
+ } else {
+ /* FMOV */
+ gen_load_fir(ctx, rb, 0);
+ gen_store_fir(ctx, rc, 0);
+ }
+ } else {
+ gen_farith3(ctx, &gen_op_cpys, ra, rb, rc);
+ }
+ break;
+ case 0x021:
+ /* CPYSN */
+ gen_farith2(ctx, &gen_op_cpysn, rb, rc);
+ break;
+ case 0x022:
+ /* CPYSE */
+ gen_farith2(ctx, &gen_op_cpyse, rb, rc);
+ break;
+ case 0x024:
+ /* MT_FPCR */
+ gen_load_fir(ctx, ra, 0);
+ gen_op_store_fpcr();
+ break;
+ case 0x025:
+ /* MF_FPCR */
+ gen_op_load_fpcr();
+ gen_store_fir(ctx, ra, 0);
+ break;
+ case 0x02A:
+ /* FCMOVEQ */
+ gen_fcmov(ctx, &gen_op_cmpfeq, ra, rb, rc);
+ break;
+ case 0x02B:
+ /* FCMOVNE */
+ gen_fcmov(ctx, &gen_op_cmpfne, ra, rb, rc);
+ break;
+ case 0x02C:
+ /* FCMOVLT */
+ gen_fcmov(ctx, &gen_op_cmpflt, ra, rb, rc);
+ break;
+ case 0x02D:
+ /* FCMOVGE */
+ gen_fcmov(ctx, &gen_op_cmpfge, ra, rb, rc);
+ break;
+ case 0x02E:
+ /* FCMOVLE */
+ gen_fcmov(ctx, &gen_op_cmpfle, ra, rb, rc);
+ break;
+ case 0x02F:
+ /* FCMOVGT */
+ gen_fcmov(ctx, &gen_op_cmpfgt, ra, rb, rc);
+ break;
+ case 0x030:
+ /* CVTQL */
+ gen_farith2(ctx, &gen_op_cvtql, rb, rc);
+ break;
+ case 0x130:
+ /* CVTQL/V */
+ gen_farith2(ctx, &gen_op_cvtqlv, rb, rc);
+ break;
+ case 0x530:
+ /* CVTQL/SV */
+ gen_farith2(ctx, &gen_op_cvtqlsv, rb, rc);
+ break;
+ default:
+ goto invalid_opc;
+ }
+ break;
+ case 0x18:
+ switch ((uint16_t)disp16) {
+ case 0x0000:
+ /* TRAPB */
+ /* No-op. Just exit from the current tb */
+ ret = 2;
+ break;
+ case 0x0400:
+ /* EXCB */
+ /* No-op. Just exit from the current tb */
+ ret = 2;
+ break;
+ case 0x4000:
+ /* MB */
+ /* No-op */
+ break;
+ case 0x4400:
+ /* WMB */
+ /* No-op */
+ break;
+ case 0x8000:
+ /* FETCH */
+ /* No-op */
+ break;
+ case 0xA000:
+ /* FETCH_M */
+ /* No-op */
+ break;
+ case 0xC000:
+ /* RPCC */
+ gen_op_load_pcc();
+ gen_store_ir(ctx, ra, 0);
+ break;
+ case 0xE000:
+ /* RC */
+ gen_op_load_irf();
+ gen_store_ir(ctx, ra, 0);
+ gen_op_clear_irf();
+ break;
+ case 0xE800:
+ /* ECB */
+ /* XXX: TODO: evict tb cache at address rb */
+#if 0
+ ret = 2;
+#else
+ goto invalid_opc;
+#endif
+ break;
+ case 0xF000:
+ /* RS */
+ gen_op_load_irf();
+ gen_store_ir(ctx, ra, 0);
+ gen_op_set_irf();
+ break;
+ case 0xF800:
+ /* WH64 */
+ /* No-op */
+ break;
+ default:
+ goto invalid_opc;
+ }
+ break;
+ case 0x19:
+ /* HW_MFPR (PALcode) */
+#if defined (CONFIG_USER_ONLY)
+ goto invalid_opc;
+#else
+ if (!ctx->pal_mode)
+ goto invalid_opc;
+ gen_op_mfpr(insn & 0xFF);
+ gen_store_ir(ctx, ra, 0);
+ break;
+#endif
+ case 0x1A:
+ gen_load_ir(ctx, rb, 0);
+ if (ra != 31) {
+ gen_set_uT1(ctx, ctx->pc);
+ gen_store_ir(ctx, ra, 1);
+ }
+ gen_op_branch();
+ /* Those four jumps only differ by the branch prediction hint */
+ switch (fn2) {
+ case 0x0:
+ /* JMP */
+ break;
+ case 0x1:
+ /* JSR */
+ break;
+ case 0x2:
+ /* RET */
+ break;
+ case 0x3:
+ /* JSR_COROUTINE */
+ break;
+ }
+ ret = 1;
+ break;
+ case 0x1B:
+ /* HW_LD (PALcode) */
+#if defined (CONFIG_USER_ONLY)
+ goto invalid_opc;
+#else
+ if (!ctx->pal_mode)
+ goto invalid_opc;
+ gen_load_ir(ctx, rb, 0);
+ gen_set_sT1(ctx, disp12);
+ gen_op_addq();
+ switch ((insn >> 12) & 0xF) {
+ case 0x0:
+ /* Longword physical access */
+ gen_op_ldl_raw();
+ break;
+ case 0x1:
+ /* Quadword physical access */
+ gen_op_ldq_raw();
+ break;
+ case 0x2:
+ /* Longword physical access with lock */
+ gen_op_ldl_l_raw();
+ break;
+ case 0x3:
+ /* Quadword physical access with lock */
+ gen_op_ldq_l_raw();
+ break;
+ case 0x4:
+ /* Longword virtual PTE fetch */
+ gen_op_ldl_kernel();
+ break;
+ case 0x5:
+ /* Quadword virtual PTE fetch */
+ gen_op_ldq_kernel();
+ break;
+ case 0x6:
+ /* Invalid */
+ goto invalid_opc;
+ case 0x7:
+ /* Invalid */
+ goto invalid_opc;
+ case 0x8:
+ /* Longword virtual access */
+ gen_op_ld_phys_to_virt();
+ gen_op_ldl_raw();
+ break;
+ case 0x9:
+ /* Quadword virtual access */
+ gen_op_ld_phys_to_virt();
+ gen_op_ldq_raw();
+ break;
+ case 0xA:
+ /* Longword virtual access with protection check */
+ gen_ldl(ctx);
+ break;
+ case 0xB:
+ /* Quadword virtual access with protection check */
+ gen_ldq(ctx);
+ break;
+ case 0xC:
+ /* Longword virtual access with altenate access mode */
+ gen_op_set_alt_mode();
+ gen_op_ld_phys_to_virt();
+ gen_op_ldl_raw();
+ gen_op_restore_mode();
+ break;
+ case 0xD:
+ /* Quadword virtual access with altenate access mode */
+ gen_op_set_alt_mode();
+ gen_op_ld_phys_to_virt();
+ gen_op_ldq_raw();
+ gen_op_restore_mode();
+ break;
+ case 0xE:
+ /* Longword virtual access with alternate access mode and
+ * protection checks
+ */
+ gen_op_set_alt_mode();
+ gen_op_ldl_data();
+ gen_op_restore_mode();
+ break;
+ case 0xF:
+ /* Quadword virtual access with alternate access mode and
+ * protection checks
+ */
+ gen_op_set_alt_mode();
+ gen_op_ldq_data();
+ gen_op_restore_mode();
+ break;
+ }
+ gen_store_ir(ctx, ra, 1);
+ break;
+#endif
+ case 0x1C:
+ switch (fn7) {
+ case 0x00:
+ /* SEXTB */
+ if (!(ctx->amask & AMASK_BWX))
+ goto invalid_opc;
+ gen_arith2(ctx, &gen_op_sextb, rb, rc, islit, lit);
+ break;
+ case 0x01:
+ /* SEXTW */
+ if (!(ctx->amask & AMASK_BWX))
+ goto invalid_opc;
+ gen_arith2(ctx, &gen_op_sextw, rb, rc, islit, lit);
+ break;
+ case 0x30:
+ /* CTPOP */
+ if (!(ctx->amask & AMASK_CIX))
+ goto invalid_opc;
+ gen_arith2(ctx, &gen_op_ctpop, rb, rc, 0, 0);
+ break;
+ case 0x31:
+ /* PERR */
+ if (!(ctx->amask & AMASK_MVI))
+ goto invalid_opc;
+ /* XXX: TODO */
+ goto invalid_opc;
+ break;
+ case 0x32:
+ /* CTLZ */
+ if (!(ctx->amask & AMASK_CIX))
+ goto invalid_opc;
+ gen_arith2(ctx, &gen_op_ctlz, rb, rc, 0, 0);
+ break;
+ case 0x33:
+ /* CTTZ */
+ if (!(ctx->amask & AMASK_CIX))
+ goto invalid_opc;
+ gen_arith2(ctx, &gen_op_cttz, rb, rc, 0, 0);
+ break;
+ case 0x34:
+ /* UNPKBW */
+ if (!(ctx->amask & AMASK_MVI))
+ goto invalid_opc;
+ /* XXX: TODO */
+ goto invalid_opc;
+ break;
+ case 0x35:
+ /* UNPKWL */
+ if (!(ctx->amask & AMASK_MVI))
+ goto invalid_opc;
+ /* XXX: TODO */
+ goto invalid_opc;
+ break;
+ case 0x36:
+ /* PKWB */
+ if (!(ctx->amask & AMASK_MVI))
+ goto invalid_opc;
+ /* XXX: TODO */
+ goto invalid_opc;
+ break;
+ case 0x37:
+ /* PKLB */
+ if (!(ctx->amask & AMASK_MVI))
+ goto invalid_opc;
+ /* XXX: TODO */
+ goto invalid_opc;
+ break;
+ case 0x38:
+ /* MINSB8 */
+ if (!(ctx->amask & AMASK_MVI))
+ goto invalid_opc;
+ /* XXX: TODO */
+ goto invalid_opc;
+ break;
+ case 0x39:
+ /* MINSW4 */
+ if (!(ctx->amask & AMASK_MVI))
+ goto invalid_opc;
+ /* XXX: TODO */
+ goto invalid_opc;
+ break;
+ case 0x3A:
+ /* MINUB8 */
+ if (!(ctx->amask & AMASK_MVI))
+ goto invalid_opc;
+ /* XXX: TODO */
+ goto invalid_opc;
+ break;
+ case 0x3B:
+ /* MINUW4 */
+ if (!(ctx->amask & AMASK_MVI))
+ goto invalid_opc;
+ /* XXX: TODO */
+ goto invalid_opc;
+ break;
+ case 0x3C:
+ /* MAXUB8 */
+ if (!(ctx->amask & AMASK_MVI))
+ goto invalid_opc;
+ /* XXX: TODO */
+ goto invalid_opc;
+ break;
+ case 0x3D:
+ /* MAXUW4 */
+ if (!(ctx->amask & AMASK_MVI))
+ goto invalid_opc;
+ /* XXX: TODO */
+ goto invalid_opc;
+ break;
+ case 0x3E:
+ /* MAXSB8 */
+ if (!(ctx->amask & AMASK_MVI))
+ goto invalid_opc;
+ /* XXX: TODO */
+ goto invalid_opc;
+ break;
+ case 0x3F:
+ /* MAXSW4 */
+ if (!(ctx->amask & AMASK_MVI))
+ goto invalid_opc;
+ /* XXX: TODO */
+ goto invalid_opc;
+ break;
+ case 0x70:
+ /* FTOIT */
+ if (!(ctx->amask & AMASK_FIX))
+ goto invalid_opc;
+ gen_fti(ctx, &gen_op_ftoit, ra, rb);
+ break;
+ case 0x78:
+ /* FTOIS */
+ if (!(ctx->amask & AMASK_FIX))
+ goto invalid_opc;
+ gen_fti(ctx, &gen_op_ftois, ra, rb);
+ break;
+ default:
+ goto invalid_opc;
+ }
+ break;
+ case 0x1D:
+ /* HW_MTPR (PALcode) */
+#if defined (CONFIG_USER_ONLY)
+ goto invalid_opc;
+#else
+ if (!ctx->pal_mode)
+ goto invalid_opc;
+ gen_load_ir(ctx, ra, 0);
+ gen_op_mtpr(insn & 0xFF);
+ ret = 2;
+ break;
+#endif
+ case 0x1E:
+ /* HW_REI (PALcode) */
+#if defined (CONFIG_USER_ONLY)
+ goto invalid_opc;
+#else
+ if (!ctx->pal_mode)
+ goto invalid_opc;
+ if (rb == 31) {
+ /* "Old" alpha */
+ gen_op_hw_rei();
+ } else {
+ gen_load_ir(ctx, rb, 0);
+ gen_set_uT1(ctx, (((int64_t)insn << 51) >> 51));
+ gen_op_addq();
+ gen_op_hw_ret();
+ }
+ ret = 2;
+ break;
+#endif
+ case 0x1F:
+ /* HW_ST (PALcode) */
+#if defined (CONFIG_USER_ONLY)
+ goto invalid_opc;
+#else
+ if (!ctx->pal_mode)
+ goto invalid_opc;
+ gen_load_ir(ctx, rb, 0);
+ gen_set_sT1(ctx, disp12);
+ gen_op_addq();
+ gen_load_ir(ctx, ra, 1);
+ switch ((insn >> 12) & 0xF) {
+ case 0x0:
+ /* Longword physical access */
+ gen_op_stl_raw();
+ break;
+ case 0x1:
+ /* Quadword physical access */
+ gen_op_stq_raw();
+ break;
+ case 0x2:
+ /* Longword physical access with lock */
+ gen_op_stl_c_raw();
+ break;
+ case 0x3:
+ /* Quadword physical access with lock */
+ gen_op_stq_c_raw();
+ break;
+ case 0x4:
+ /* Longword virtual access */
+ gen_op_st_phys_to_virt();
+ gen_op_stl_raw();
+ break;
+ case 0x5:
+ /* Quadword virtual access */
+ gen_op_st_phys_to_virt();
+ gen_op_stq_raw();
+ break;
+ case 0x6:
+ /* Invalid */
+ goto invalid_opc;
+ case 0x7:
+ /* Invalid */
+ goto invalid_opc;
+ case 0x8:
+ /* Invalid */
+ goto invalid_opc;
+ case 0x9:
+ /* Invalid */
+ goto invalid_opc;
+ case 0xA:
+ /* Invalid */
+ goto invalid_opc;
+ case 0xB:
+ /* Invalid */
+ goto invalid_opc;
+ case 0xC:
+ /* Longword virtual access with alternate access mode */
+ gen_op_set_alt_mode();
+ gen_op_st_phys_to_virt();
+ gen_op_ldl_raw();
+ gen_op_restore_mode();
+ break;
+ case 0xD:
+ /* Quadword virtual access with alternate access mode */
+ gen_op_set_alt_mode();
+ gen_op_st_phys_to_virt();
+ gen_op_ldq_raw();
+ gen_op_restore_mode();
+ break;
+ case 0xE:
+ /* Invalid */
+ goto invalid_opc;
+ case 0xF:
+ /* Invalid */
+ goto invalid_opc;
+ }
+ ret = 2;
+ break;
+#endif
+ case 0x20:
+ /* LDF */
+#if 0 // TODO
+ gen_load_fmem(ctx, &gen_ldf, ra, rb, disp16);
+#else
+ goto invalid_opc;
+#endif
+ break;
+ case 0x21:
+ /* LDG */
+#if 0 // TODO
+ gen_load_fmem(ctx, &gen_ldg, ra, rb, disp16);
+#else
+ goto invalid_opc;
+#endif
+ break;
+ case 0x22:
+ /* LDS */
+ gen_load_fmem(ctx, &gen_lds, ra, rb, disp16);
+ break;
+ case 0x23:
+ /* LDT */
+ gen_load_fmem(ctx, &gen_ldt, ra, rb, disp16);
+ break;
+ case 0x24:
+ /* STF */
+#if 0 // TODO
+ gen_store_fmem(ctx, &gen_stf, ra, rb, disp16);
+#else
+ goto invalid_opc;
+#endif
+ break;
+ case 0x25:
+ /* STG */
+#if 0 // TODO
+ gen_store_fmem(ctx, &gen_stg, ra, rb, disp16);
+#else
+ goto invalid_opc;
+#endif
+ break;
+ case 0x26:
+ /* STS */
+ gen_store_fmem(ctx, &gen_sts, ra, rb, disp16);
+ break;
+ case 0x27:
+ /* STT */
+ gen_store_fmem(ctx, &gen_stt, ra, rb, disp16);
+ break;
+ case 0x28:
+ /* LDL */
+ gen_load_mem(ctx, &gen_ldl, ra, rb, disp16, 0);
+ break;
+ case 0x29:
+ /* LDQ */
+ gen_load_mem(ctx, &gen_ldq, ra, rb, disp16, 0);
+ break;
+ case 0x2A:
+ /* LDL_L */
+ gen_load_mem(ctx, &gen_ldl_l, ra, rb, disp16, 0);
+ break;
+ case 0x2B:
+ /* LDQ_L */
+ gen_load_mem(ctx, &gen_ldq_l, ra, rb, disp16, 0);
+ break;
+ case 0x2C:
+ /* STL */
+ gen_store_mem(ctx, &gen_stl, ra, rb, disp16, 0);
+ break;
+ case 0x2D:
+ /* STQ */
+ gen_store_mem(ctx, &gen_stq, ra, rb, disp16, 0);
+ break;
+ case 0x2E:
+ /* STL_C */
+ gen_store_mem(ctx, &gen_stl_c, ra, rb, disp16, 0);
+ break;
+ case 0x2F:
+ /* STQ_C */
+ gen_store_mem(ctx, &gen_stq_c, ra, rb, disp16, 0);
+ break;
+ case 0x30:
+ /* BR */
+ gen_set_uT0(ctx, ctx->pc);
+ gen_store_ir(ctx, ra, 0);
+ if (disp21 != 0) {
+ gen_set_sT1(ctx, disp21 << 2);
+ gen_op_addq();
+ }
+ gen_op_branch();
+ ret = 1;
+ break;
+ case 0x31:
+ /* FBEQ */
+ gen_fbcond(ctx, &gen_op_cmpfeq, ra, disp16);
+ ret = 1;
+ break;
+ case 0x32:
+ /* FBLT */
+ gen_fbcond(ctx, &gen_op_cmpflt, ra, disp16);
+ ret = 1;
+ break;
+ case 0x33:
+ /* FBLE */
+ gen_fbcond(ctx, &gen_op_cmpfle, ra, disp16);
+ ret = 1;
+ break;
+ case 0x34:
+ /* BSR */
+ gen_set_uT0(ctx, ctx->pc);
+ gen_store_ir(ctx, ra, 0);
+ if (disp21 != 0) {
+ gen_set_sT1(ctx, disp21 << 2);
+ gen_op_addq();
+ }
+ gen_op_branch();
+ ret = 1;
+ break;
+ case 0x35:
+ /* FBNE */
+ gen_fbcond(ctx, &gen_op_cmpfne, ra, disp16);
+ ret = 1;
+ break;
+ case 0x36:
+ /* FBGE */
+ gen_fbcond(ctx, &gen_op_cmpfge, ra, disp16);
+ ret = 1;
+ break;
+ case 0x37:
+ /* FBGT */
+ gen_fbcond(ctx, &gen_op_cmpfgt, ra, disp16);
+ ret = 1;
+ break;
+ case 0x38:
+ /* BLBC */
+ gen_bcond(ctx, &gen_op_cmplbc, ra, disp16);
+ ret = 1;
+ break;
+ case 0x39:
+ /* BEQ */
+ gen_bcond(ctx, &gen_op_cmpeqz, ra, disp16);
+ ret = 1;
+ break;
+ case 0x3A:
+ /* BLT */
+ gen_bcond(ctx, &gen_op_cmpltz, ra, disp16);
+ ret = 1;
+ break;
+ case 0x3B:
+ /* BLE */
+ gen_bcond(ctx, &gen_op_cmplez, ra, disp16);
+ ret = 1;
+ break;
+ case 0x3C:
+ /* BLBS */
+ gen_bcond(ctx, &gen_op_cmplbs, ra, disp16);
+ ret = 1;
+ break;
+ case 0x3D:
+ /* BNE */
+ gen_bcond(ctx, &gen_op_cmpnez, ra, disp16);
+ ret = 1;
+ break;
+ case 0x3E:
+ /* BGE */
+ gen_bcond(ctx, &gen_op_cmpgez, ra, disp16);
+ ret = 1;
+ break;
+ case 0x3F:
+ /* BGT */
+ gen_bcond(ctx, &gen_op_cmpgtz, ra, disp16);
+ ret = 1;
+ break;
+ invalid_opc:
+ gen_invalid(ctx);
+ ret = 3;
+ break;
+ }
+
+ return ret;
+}
+
+int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
+ int search_pc)
+{
+#if defined ALPHA_DEBUG_DISAS
+ static int insn_count;
+#endif
+ DisasContext ctx, *ctxp = &ctx;
+ target_ulong pc_start;
+ uint32_t insn;
+ uint16_t *gen_opc_end;
+ int j, lj = -1;
+ int ret;
+
+ pc_start = tb->pc;
+ gen_opc_ptr = gen_opc_buf;
+ gen_opc_end = gen_opc_buf + OPC_MAX_SIZE;
+ gen_opparam_ptr = gen_opparam_buf;
+ nb_gen_labels = 0;
+ ctx.pc = pc_start;
+ ctx.amask = env->amask;
+#if defined (CONFIG_USER_ONLY)
+ ctx.mem_idx = 0;
+#else
+ ctx.mem_idx = ((env->ps >> 3) & 3);
+ ctx.pal_mode = env->ipr[IPR_EXC_ADDR] & 1;
+#endif
+ for (ret = 0; ret == 0;) {
+ if (env->nb_breakpoints > 0) {
+ for(j = 0; j < env->nb_breakpoints; j++) {
+ if (env->breakpoints[j] == ctx.pc) {
+ gen_excp(&ctx, EXCP_DEBUG, 0);
+ 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] = ctx.pc;
+ gen_opc_instr_start[lj] = 1;
+ }
+ }
+#if defined ALPHA_DEBUG_DISAS
+ insn_count++;
+ if (logfile != NULL) {
+ fprintf(logfile, "pc " TARGET_FMT_lx " mem_idx %d\n",
+ ctx.pc, ctx.mem_idx);
+ }
+#endif
+ insn = ldl_code(ctx.pc);
+#if defined ALPHA_DEBUG_DISAS
+ insn_count++;
+ if (logfile != NULL) {
+ fprintf(logfile, "opcode %08x %d\n", insn, insn_count);
+ }
+#endif
+ ctx.pc += 4;
+ ret = translate_one(ctxp, insn);
+ if (ret != 0)
+ break;
+ /* if we reach a page boundary or are single stepping, stop
+ * generation
+ */
+ if (((ctx.pc & (TARGET_PAGE_SIZE - 1)) == 0) ||
+ (env->singlestep_enabled)) {
+ break;
+ }
+#if defined (DO_SINGLE_STEP)
+ break;
+#endif
+ }
+ if (ret != 1 && ret != 3) {
+ gen_update_pc(&ctx);
+ }
+ gen_op_reset_T0();
+#if defined (DO_TB_FLUSH)
+ gen_op_tb_flush();
+#endif
+ /* Generate the return instruction */
+ gen_op_exit_tb();
+ *gen_opc_ptr = INDEX_op_end;
+ if (search_pc) {
+ j = gen_opc_ptr - gen_opc_buf;
+ lj++;
+ while (lj <= j)
+ gen_opc_instr_start[lj++] = 0;
+ tb->size = 0;
+ } else {
+ tb->size = ctx.pc - pc_start;
+ }
+#if defined ALPHA_DEBUG_DISAS
+ if (loglevel & CPU_LOG_TB_CPU) {
+ cpu_dump_state(env, logfile, fprintf, 0);
+ }
+ if (loglevel & CPU_LOG_TB_IN_ASM) {
+ fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
+ target_disas(logfile, pc_start, ctx.pc - pc_start, 1);
+ fprintf(logfile, "\n");
+ }
+ if (loglevel & CPU_LOG_TB_OP) {
+ fprintf(logfile, "OP:\n");
+ dump_ops(gen_opc_buf, gen_opparam_buf);
+ fprintf(logfile, "\n");
+ }
+#endif
+
+ return 0;
+}
+
+int gen_intermediate_code (CPUState *env, struct TranslationBlock *tb)
+{
+ return gen_intermediate_code_internal(env, tb, 0);
+}
+
+int gen_intermediate_code_pc (CPUState *env, struct TranslationBlock *tb)
+{
+ return gen_intermediate_code_internal(env, tb, 1);
+}
+
+CPUAlphaState * cpu_alpha_init (void)
+{
+ CPUAlphaState *env;
+ uint64_t hwpcb;
+
+ env = qemu_mallocz(sizeof(CPUAlphaState));
+ if (!env)
+ return NULL;
+ cpu_exec_init(env);
+ tlb_flush(env, 1);
+ /* XXX: should not be hardcoded */
+ env->implver = IMPLVER_2106x;
+ env->ps = 0x1F00;
+#if defined (CONFIG_USER_ONLY)
+ env->ps |= 1 << 3;
+#endif
+ pal_init(env);
+ /* Initialize IPR */
+ hwpcb = env->ipr[IPR_PCBB];
+ env->ipr[IPR_ASN] = 0;
+ env->ipr[IPR_ASTEN] = 0;
+ env->ipr[IPR_ASTSR] = 0;
+ env->ipr[IPR_DATFX] = 0;
+ /* XXX: fix this */
+ // env->ipr[IPR_ESP] = ldq_raw(hwpcb + 8);
+ // env->ipr[IPR_KSP] = ldq_raw(hwpcb + 0);
+ // env->ipr[IPR_SSP] = ldq_raw(hwpcb + 16);
+ // env->ipr[IPR_USP] = ldq_raw(hwpcb + 24);
+ env->ipr[IPR_FEN] = 0;
+ env->ipr[IPR_IPL] = 31;
+ env->ipr[IPR_MCES] = 0;
+ env->ipr[IPR_PERFMON] = 0; /* Implementation specific */
+ // env->ipr[IPR_PTBR] = ldq_raw(hwpcb + 32);
+ env->ipr[IPR_SISR] = 0;
+ env->ipr[IPR_VIRBND] = -1ULL;
+
+ return env;
+}
Modified: trunk/src/host/qemu-neo1973/target-arm/cpu.h
===================================================================
--- trunk/src/host/qemu-neo1973/target-arm/cpu.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/target-arm/cpu.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -38,9 +38,10 @@
#define EXCP_FIQ 6
#define EXCP_BKPT 7
-typedef void ARMWriteCPFunc(void *opaque,
- int op2, int reg, int crm, uint32_t value);
-typedef uint32_t ARMReadCPFunc(void *opaque, int op2, int reg, int crm);
+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);
/* We currently assume float and double are IEEE single and double
precision respectively.
@@ -82,10 +83,14 @@
uint32_t c0_cachetype;
uint32_t c1_sys; /* System control register. */
uint32_t c1_coproc; /* Coprocessor access register. */
- uint32_t c2; /* MMU translation table base. */
- uint32_t c3; /* MMU domain access control register. */
+ uint32_t c2_base; /* MMU translation table base. */
+ 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. */
@@ -143,6 +148,13 @@
CPU_COMMON
+ /* These fields after the common ones so they are preserved on reset. */
+ int ram_size;
+ const char *kernel_filename;
+ const char *kernel_cmdline;
+ const char *initrd_filename;
+ int board_id;
+ target_phys_addr_t loader_start;
} CPUARMState;
CPUARMState *cpu_arm_init(void);
@@ -154,8 +166,7 @@
/* you can call this signal handler from your SIGBUS and SIGSEGV
signal handlers to inform the virtual CPU of exceptions. non zero
is returned if the signal was handled by the virtual CPU. */
-struct siginfo;
-int cpu_arm_signal_handler(int host_signum, struct siginfo *info,
+int cpu_arm_signal_handler(int host_signum, void *pinfo,
void *puc);
#define CPSR_M (0x1f)
@@ -236,6 +247,7 @@
ARM_FEATURE_XSCALE, /* Intel XScale extensions. */
ARM_FEATURE_IWMMXT, /* Intel iwMMXt extension. */
ARM_FEATURE_S3C, /* S3C specific bits. */
+ ARM_FEATURE_MPU /* Only has Memory Protection Unit, not full MMU. */
};
static inline int arm_feature(CPUARMState *env, int feature)
@@ -243,14 +255,16 @@
return (env->features & (1u << feature)) != 0;
}
-void cpu_arm_set_model(CPUARMState *env, uint32_t id);
+void arm_cpu_list(void);
+void cpu_arm_set_model(CPUARMState *env, const char *name);
void cpu_arm_set_cp_io(CPUARMState *env, int cpnum,
- ARMReadCPFunc *cp_read, ARMWriteCPFunc *cp_write,
- void *opaque);
+ ARMReadCPFunc *cp_read, ARMWriteCPFunc *cp_write,
+ void *opaque);
#define ARM_CPUID_ARM1026 0x4106a262
#define ARM_CPUID_ARM926 0x41069265
+#define ARM_CPUID_ARM946 0x41059461
#define ARM_CPUID_ARM920T 0x41129200
#define ARM_CPUID_PXA250 0x69052100
#define ARM_CPUID_PXA255 0x69052d00
Modified: trunk/src/host/qemu-neo1973/target-arm/exec.h
===================================================================
--- trunk/src/host/qemu-neo1973/target-arm/exec.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/target-arm/exec.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -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"
register struct CPUARMState *env asm(AREG0);
Modified: trunk/src/host/qemu-neo1973/target-arm/helper.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-arm/helper.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/target-arm/helper.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -5,56 +5,34 @@
#include "cpu.h"
#include "exec-all.h"
-void cpu_reset(CPUARMState *env)
-{
-#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;
- env->vfp.xregs[ARM_VFP_FPEXC] = 0;
-#endif
- env->regs[15] = 0;
-}
-
-CPUARMState *cpu_arm_init(void)
-{
- CPUARMState *env;
-
- env = qemu_mallocz(sizeof(CPUARMState));
- if (!env)
- return NULL;
- cpu_exec_init(env);
- cpu_reset(env);
- tlb_flush(env, 1);
- return env;
-}
-
static inline void set_feature(CPUARMState *env, int feature)
{
env->features |= 1u << feature;
}
-void cpu_arm_set_model(CPUARMState *env, uint32_t id)
+static void cpu_reset_model_id(CPUARMState *env, uint32_t id)
{
env->cp15.c0_cpuid = id;
switch (id) {
+ case ARM_CPUID_ARM920T:
+ set_feature(env, ARM_FEATURE_S3C);
+ env->cp15.c0_cachetype = 0xd172172;
+ break;
case ARM_CPUID_ARM926:
set_feature(env, ARM_FEATURE_VFP);
env->vfp.xregs[ARM_VFP_FPSID] = 0x41011090;
env->cp15.c0_cachetype = 0x1dd20d2;
break;
+ case ARM_CPUID_ARM946:
+ set_feature(env, ARM_FEATURE_MPU);
+ env->cp15.c0_cachetype = 0x0f004006;
+ 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;
break;
- case ARM_CPUID_ARM920T:
- set_feature(env, ARM_FEATURE_S3C);
- env->cp15.c0_cachetype = 0xd172172;
- break;
case ARM_CPUID_PXA250:
case ARM_CPUID_PXA255:
case ARM_CPUID_PXA260:
@@ -82,6 +60,92 @@
}
}
+void cpu_reset(CPUARMState *env)
+{
+ uint32_t id;
+ 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;
+ env->vfp.xregs[ARM_VFP_FPEXC] = 0;
+#endif
+ env->regs[15] = 0;
+ tlb_flush(env, 1);
+}
+
+CPUARMState *cpu_arm_init(void)
+{
+ CPUARMState *env;
+
+ env = qemu_mallocz(sizeof(CPUARMState));
+ if (!env)
+ return NULL;
+ cpu_exec_init(env);
+ cpu_reset(env);
+ return env;
+}
+
+struct arm_cpu_t {
+ uint32_t id;
+ const char *name;
+};
+
+static const struct arm_cpu_t arm_cpu_names[] = {
+ { ARM_CPUID_ARM920T, "arm920t"},
+ { ARM_CPUID_ARM926, "arm926"},
+ { ARM_CPUID_ARM946, "arm946"},
+ { ARM_CPUID_ARM1026, "arm1026"},
+ { 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" },
+ { 0, NULL}
+};
+
+void arm_cpu_list(void)
+{
+ int i;
+
+ printf ("Available CPUs:\n");
+ for (i = 0; arm_cpu_names[i].name; i++) {
+ printf(" %s\n", arm_cpu_names[i].name);
+ }
+}
+
+void cpu_arm_set_model(CPUARMState *env, const char *name)
+{
+ int i;
+ uint32_t id;
+
+ id = 0;
+ i = 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;
+ }
+ }
+ if (!id) {
+ cpu_abort(env, "Unknown CPU '%s'", name);
+ return;
+ }
+ cpu_reset_model_id(env, id);
+}
+
void cpu_arm_close(CPUARMState *env)
{
free(env);
@@ -107,12 +171,26 @@
return 1;
}
-target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
+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);
@@ -132,6 +210,8 @@
#else
+extern int semihosting_enabled;
+
/* Map CPU modes onto saved register banks. */
static inline int bank_number (int mode)
{
@@ -202,6 +282,22 @@
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;
@@ -306,13 +402,67 @@
address += env->cp15.c13_fcse;
if ((env->cp15.c1_sys & 1) == 0) {
- /* MMU diusabled. */
+ /* MMU/MPU disabled. */
*phys_ptr = address;
*prot = PAGE_READ | PAGE_WRITE;
+ } else if (arm_feature(env, ARM_FEATURE_MPU)) {
+ 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;
+ }
} else {
/* Pagetable walk. */
/* Lookup l1 descriptor. */
- table = (env->cp15.c2 & 0xffffc000) | ((address >> 18) & 0x3ffc);
+ table = (env->cp15.c2_base & 0xffffc000) | ((address >> 18) & 0x3ffc);
desc = ldl_phys(table);
type = (desc & 3);
domain = (env->cp15.c3 >> ((desc >> 4) & 0x1e)) & 3;
@@ -333,9 +483,15 @@
phys_addr = (desc & 0xfff00000) | (address & 0x000fffff);
ap = (desc >> 10) & 3;
code = 13;
- } else if (type == 1) {
+ } else {
/* Lookup l2 entry. */
- table = (desc & 0xfffffc00) | ((address >> 10) & 0x3fc);
+ 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. */
@@ -367,11 +523,7 @@
abort();
}
code = 15;
- } else {
- code = 15;
- goto do_fault;
}
-
*prot = check_ap(env, ap, domain, access_type, is_user);
if (!*prot) {
/* Access permission fault. */
@@ -412,7 +564,7 @@
return 1;
}
-target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
+target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
{
uint32_t phys_addr;
int prot;
@@ -428,51 +580,73 @@
void helper_set_cp(CPUState *env, uint32_t insn, uint32_t val)
{
- int op1 = (insn >> 8) & 0xf;
- int op2 = (insn >> 5) & 7;
- int reg = (insn >> 16) & 0xf;
- int crm = insn & 0xf;
+ int cp_num = (insn >> 8) & 0xf;
+ int cp_info = (insn >> 5) & 7;
+ int src = (insn >> 16) & 0xf;
+ int operand = insn & 0xf;
- /* On XScale coprocessors [0, 13] have to be enabled in CPAR. */
- if (arm_feature(env, ARM_FEATURE_XSCALE)) {
- if (op1 <= 13 && (env->cp15.c15_cpar & (1 << op1)) == 0)
- return; /* Permission Denied */
- }
-
- if (env->cp[op1].cp_write)
- env->cp[op1].cp_write(env->cp[op1].opaque, op2, reg, crm, val);
+ 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 op1 = (insn >> 8) & 0xf;
- int op2 = (insn >> 5) & 7;
- int reg = (insn >> 16) & 0xf;
- int crm = insn & 0xf;
+ int cp_num = (insn >> 8) & 0xf;
+ int cp_info = (insn >> 5) & 7;
+ int dest = (insn >> 16) & 0xf;
+ int operand = insn & 0xf;
- /* On XScale coprocessors [0, 13] have to be enabled in CPAR. */
- if (arm_feature(env, ARM_FEATURE_XSCALE)) {
- if (op1 <= 13 && (env->cp15.c15_cpar & (1 << op1)) == 0)
- return 0; /* Permission Denied */
+ 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;
+}
- if (env->cp[op1].cp_read)
- return env->cp[op1].cp_read(env->cp[op1].opaque, op2, reg, crm);
- return 0;
+/* 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)
{
uint32_t op2;
+ uint32_t crm;
op2 = (insn >> 5) & 7;
+ crm = insn & 0xf;
switch ((insn >> 16) & 0xf) {
case 0: /* ID codes. */
goto bad_reg;
case 1: /* System configuration. */
switch (op2) {
case 0:
- if (!arm_feature(env, ARM_FEATURE_XSCALE) || (insn & 0xf) == 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. */
@@ -493,38 +667,71 @@
goto bad_reg;
}
break;
- case 2: /* MMU Page table control. */
- env->cp15.c2 = val;
+ 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 {
+ env->cp15.c2_base = val;
+ }
break;
- case 3: /* MMU Domain access control. */
+ case 3: /* MMU Domain access control / MPU write buffer control. */
env->cp15.c3 = val;
break;
case 4: /* Reserved. */
goto bad_reg;
- case 5: /* MMU Fault status. */
+ case 5: /* MMU Fault status / MPU access permission. */
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;
- default:
- goto bad_reg;
- }
- break;
- case 6: /* MMU Fault address. */
- switch (op2) {
- case 0:
- env->cp15.c6_data = val;
+ case 2:
+ if (!arm_feature(env, ARM_FEATURE_MPU))
+ goto bad_reg;
+ env->cp15.c5_data = val;
break;
- case 1:
- env->cp15.c6_insn = val;
+ 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 {
+ switch (op2) {
+ case 0:
+ env->cp15.c6_data = val;
+ break;
+ case 1:
+ env->cp15.c6_insn = val;
+ break;
+ default:
+ goto bad_reg;
+ }
+ }
+ break;
case 7: /* Cache control. */
/* No cache, so nothing to do. */
break;
@@ -551,14 +758,23 @@
goto bad_reg;
}
break;
- case 9: /* Cache lockdown. */
- switch (op2) {
- case 0:
- env->cp15.c9_data = val;
+ case 9:
+ switch (crm) {
+ case 0: /* Cache lockdown. */
+ 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:
- env->cp15.c9_insn = val;
- break;
+ case 1: /* TCM memory region registers. */
+ /* Not implemented. */
+ goto bad_reg;
default:
goto bad_reg;
}
@@ -566,7 +782,6 @@
case 10: /* MMU TLB lockdown. */
/* ??? TLB lockdown not implemented. */
break;
- case 11: /* TCM DMA control. */
case 12: /* Reserved. */
goto bad_reg;
case 13: /* Process ID. */
@@ -574,6 +789,8 @@
op2 = 0;
switch (op2) {
case 0:
+ if (!arm_feature(env, ARM_FEATURE_MPU))
+ goto bad_reg;
/* Unlike real hardware the qemu TLB uses virtual addresses,
not modified virtual addresses, so this causes a TLB flush.
*/
@@ -583,7 +800,8 @@
break;
case 1:
/* This changes the ASID, so do a TLB flush. */
- if (env->cp15.c13_context != val)
+ if (env->cp15.c13_context != val
+ && !arm_feature(env, ARM_FEATURE_MPU))
tlb_flush(env, 0);
env->cp15.c13_context = val;
break;
@@ -595,8 +813,10 @@
goto bad_reg;
case 15: /* Implementation specific. */
if (arm_feature(env, ARM_FEATURE_XSCALE)) {
- if (op2 == 0 && (insn & 0xf) == 1) {
- env->cp15.c15_cpar = val & 0x3fff;
+ if (op2 == 0 && crm == 1) {
+ /* Changes cp0 to cp13 behavior, so needs a TB flush. */
+ tb_flush(env);
+ env->cp15.c15_cpar = (val & 0x3fff) | 2;
break;
}
goto bad_reg;
@@ -624,7 +844,6 @@
case 2: /* TCM status. */
if (arm_feature(env, ARM_FEATURE_S3C))
return env->cp15.c0_cpuid;
- return 0;
}
case 1: /* System configuration. */
switch (op2) {
@@ -641,34 +860,67 @@
default:
goto bad_reg;
}
- case 2: /* MMU Page table control. */
- return env->cp15.c2;
- case 3: /* MMU Domain access control. */
+ 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 {
+ return env->cp15.c2_base;
+ }
+ 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. */
+ case 5: /* MMU Fault status / MPU access permission. */
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. */
- switch (op2) {
- case 0:
- return env->cp15.c6_data;
- case 1:
- /* Arm9 doesn't have an IFAR, but implementing it anyway shouldn't
- do any harm. */
- return env->cp15.c6_insn;
- default:
- goto bad_reg;
+ case 6: /* MMU Fault address / MPU base/size. */
+ if (arm_feature(env, ARM_FEATURE_MPU)) {
+ int n;
+ n = (insn & 0xf);
+ if (n >= 8)
+ goto bad_reg;
+ return env->cp15.c6_region[n];
+ } else {
+ switch (op2) {
+ case 0:
+ return env->cp15.c6_data;
+ case 1:
+ /* Arm9 doesn't have an IFAR, but implementing it anyway
+ shouldn't do any harm. */
+ return env->cp15.c6_insn;
+ default:
+ goto bad_reg;
+ }
}
case 7: /* Cache control. */
- /* ??? This is for test, clean and invaidate operations that set the
+ /* ??? This is for test, clean and invalidate operations that set the
Z flag. We can't represent N = Z = 1, so it also clears
the N flag. Oh well. */
env->NZF = 0;
Modified: trunk/src/host/qemu-neo1973/target-arm/op.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-arm/op.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/target-arm/op.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -1214,691 +1214,5 @@
T0 = T2;
}
-/* iwMMXt support. */
-
-#define M1 env->iwmmxt.regs[PARAM1]
-
-/* 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) ((a) & 0x80 ? ((a) | 0xff00) : (a))
-#define EXTEND8(a) ((a) & 0x80 ? ((a) | 0xffffff00) : (a))
-#define EXTEND16(a) ((a) & 0x8000 ? ((a) | 0xffff0000) : (a))
-#define EXTEND32(a) ((a) & 0x80000000ULL ? \
- ((a) | 0xffffffff00000000ULL) : (a))
-
-void OPPROTO op_iwmmxt_movl_T0_T1_wRn(void)
-{
- T0 = M1 & ~(uint32_t) 0;
- T1 = M1 >> 32;
-}
-
-void OPPROTO op_iwmmxt_movl_wRn_T0_T1(void)
-{
- M1 = ((uint64_t) T1 << 32) | T0;
-}
-
-void OPPROTO op_iwmmxt_movq_M0_wRn(void)
-{
- M0 = M1;
-}
-
-void OPPROTO op_iwmmxt_orq_M0_wRn(void)
-{
- M0 |= M1;
-}
-
-void OPPROTO op_iwmmxt_andq_M0_wRn(void)
-{
- M0 &= M1;
-}
-
-void OPPROTO op_iwmmxt_xorq_M0_wRn(void)
-{
- M0 ^= M1;
-}
-
-void OPPROTO op_iwmmxt_maddsq_M0_wRn(void)
-{
- M0 = ((
- EXTEND16((M0 >> 0) & 0xffff) * EXTEND16((M1 >> 0) & 0xffff) +
- EXTEND16((M0 >> 16) & 0xffff) * EXTEND16((M1 >> 16) & 0xffff)
- ) & 0xffffffff) | ((
- EXTEND16((M0 >> 32) & 0xffff) * EXTEND16((M1 >> 32) & 0xffff) +
- EXTEND16((M0 >> 48) & 0xffff) * EXTEND16((M1 >> 48) & 0xffff)
- ) << 32);
-}
-
-void OPPROTO op_iwmmxt_madduq_M0_wRn(void)
-{
- M0 = ((
- ((M0 >> 0) & 0xffff) * ((M1 >> 0) & 0xffff) +
- ((M0 >> 16) & 0xffff) * ((M1 >> 16) & 0xffff)
- ) & 0xffffffff) | ((
- ((M0 >> 32) & 0xffff) * ((M1 >> 32) & 0xffff) +
- ((M0 >> 48) & 0xffff) * ((M1 >> 48) & 0xffff)
- ) << 32);
-}
-
-void OPPROTO op_iwmmxt_sadb_M0_wRn(void)
-{
-#define abs(x) (((x) >= 0) ? x : -x)
-#define SADB(SHR) abs((int) ((M0 >> SHR) & 0xff) - (int) ((M1 >> SHR) & 0xff))
- M0 =
- SADB(0) + SADB(8) + SADB(16) + SADB(24) +
- SADB(32) + SADB(40) + SADB(48) + SADB(56);
-#undef SADB
-}
-
-void OPPROTO op_iwmmxt_sadw_M0_wRn(void)
-{
-#define SADW(SHR) \
- abs((int) ((M0 >> SHR) & 0xffff) - (int) ((M1 >> SHR) & 0xffff))
- M0 = SADW(0) + SADW(16) + SADW(32) + SADW(48);
-#undef SADW
-}
-
-void OPPROTO op_iwmmxt_addl_M0_wRn(void)
-{
- M0 += env->iwmmxt.regs[PARAM1] & 0xffffffff;
-}
-
-void OPPROTO op_iwmmxt_mulsw_M0_wRn(void)
-{
-#define MULS(SHR) (((( \
- EXTEND16((M0 >> SHR) & 0xffff) * EXTEND16((M1 >> SHR) & 0xffff) \
- ) >> PARAM2) & 0xffff) << SHR)
- M0 = MULS(0) | MULS(16) | MULS(32) | MULS(48);
-#undef MULS
-}
-
-void OPPROTO op_iwmmxt_muluw_M0_wRn(void)
-{
-#define MULU(SHR) (((( \
- ((M0 >> SHR) & 0xffff) * ((M1 >> SHR) & 0xffff) \
- ) >> PARAM2) & 0xffff) << SHR)
- M0 = MULU(0) | MULU(16) | MULU(32) | MULU(48);
-#undef MULU
-}
-
-void OPPROTO op_iwmmxt_macsw_M0_wRn(void)
-{
-#define MACS(SHR) ( \
- (int32_t) EXTEND16((M0 >> SHR) & 0xffff) * \
- (int32_t) EXTEND16((M1 >> SHR) & 0xffff))
- M0 = (int64_t) (MACS(0) + MACS(16) + MACS(32) + MACS(48));
-#undef MACS
-}
-
-void OPPROTO op_iwmmxt_macuw_M0_wRn(void)
-{
-#define MACU(SHR) ( \
- (uint32_t) ((M0 >> SHR) & 0xffff) * \
- (uint32_t) ((M1 >> SHR) & 0xffff))
- M0 = MACU(0) + MACU(16) + MACU(32) + MACU(48);
-#undef MACU
-}
-
-void OPPROTO op_iwmmxt_addsq_M0_wRn(void)
-{
- M0 = (int64_t) M0 + (int64_t) M1;
-}
-
-void OPPROTO op_iwmmxt_adduq_M0_wRn(void)
-{
- M0 += M1;
-}
-
-void OPPROTO op_iwmmxt_movq_wRn_M0(void)
-{
- M1 = M0;
-}
-
-void OPPROTO op_iwmmxt_movl_wCx_T0(void)
-{
- env->iwmmxt.cregs[PARAM1] = T0;
-}
-
-void OPPROTO op_iwmmxt_movl_T0_wCx(void)
-{
- T0 = env->iwmmxt.cregs[PARAM1];
-}
-
-void OPPROTO op_iwmmxt_movl_T1_wCx(void)
-{
- T1 = env->iwmmxt.cregs[PARAM1];
-}
-
-void OPPROTO op_iwmmxt_set_mup(void)
-{
- env->iwmmxt.cregs[ARM_IWMMXT_wCon] |= 2;
-}
-
-void OPPROTO op_iwmmxt_set_cup(void)
-{
- env->iwmmxt.cregs[ARM_IWMMXT_wCon] |= 1;
-}
-
-void OPPROTO op_iwmmxt_setpsr_nz(void)
-{
- env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
- SIMD64_SET((M0 == 0), SIMD_ZBIT) |
- SIMD64_SET((M0 & (1ULL << 63)), SIMD_NBIT);
-}
-
-void OPPROTO op_iwmmxt_negq_M0(void)
-{
- M0 = ~M0;
-}
-
-#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) \
-void OPPROTO glue(op_iwmmxt_unpack, glue(S, b_M0_wRn))(void) \
-{ \
- M0 = \
- (((M0 >> SH0) & 0xff) << 0) | (((M1 >> SH0) & 0xff) << 8) | \
- (((M0 >> SH1) & 0xff) << 16) | (((M1 >> SH1) & 0xff) << 24) | \
- (((M0 >> SH2) & 0xff) << 32) | (((M1 >> SH2) & 0xff) << 40) | \
- (((M0 >> SH3) & 0xff) << 48) | (((M1 >> SH3) & 0xff) << 56); \
- env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \
- NZBIT8(M0 >> 0, 0) | NZBIT8(M0 >> 8, 1) | \
- NZBIT8(M0 >> 16, 2) | NZBIT8(M0 >> 24, 3) | \
- NZBIT8(M0 >> 32, 4) | NZBIT8(M0 >> 40, 5) | \
- NZBIT8(M0 >> 48, 6) | NZBIT8(M0 >> 56, 7); \
-} \
-void OPPROTO glue(op_iwmmxt_unpack, glue(S, w_M0_wRn))(void) \
-{ \
- M0 = \
- (((M0 >> SH0) & 0xffff) << 0) | \
- (((M1 >> SH0) & 0xffff) << 16) | \
- (((M0 >> SH2) & 0xffff) << 32) | \
- (((M1 >> SH2) & 0xffff) << 48); \
- env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \
- NZBIT8(M0 >> 0, 0) | NZBIT8(M0 >> 16, 1) | \
- NZBIT8(M0 >> 32, 2) | NZBIT8(M0 >> 48, 3); \
-} \
-void OPPROTO glue(op_iwmmxt_unpack, glue(S, l_M0_wRn))(void) \
-{ \
- M0 = \
- (((M0 >> SH0) & 0xffffffff) << 0) | \
- (((M1 >> SH0) & 0xffffffff) << 32); \
- env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \
- NZBIT32(M0 >> 0, 0) | NZBIT32(M0 >> 32, 1); \
-} \
-void OPPROTO glue(op_iwmmxt_unpack, glue(S, ub_M0))(void) \
-{ \
- M0 = \
- (((M0 >> SH0) & 0xff) << 0) | \
- (((M0 >> SH1) & 0xff) << 16) | \
- (((M0 >> SH2) & 0xff) << 32) | \
- (((M0 >> SH3) & 0xff) << 48); \
- env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \
- NZBIT16(M0 >> 0, 0) | NZBIT16(M0 >> 16, 1) | \
- NZBIT16(M0 >> 32, 2) | NZBIT16(M0 >> 48, 3); \
-} \
-void OPPROTO glue(op_iwmmxt_unpack, glue(S, uw_M0))(void) \
-{ \
- M0 = \
- (((M0 >> SH0) & 0xffff) << 0) | \
- (((M0 >> SH2) & 0xffff) << 32); \
- env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \
- NZBIT32(M0 >> 0, 0) | NZBIT32(M0 >> 32, 1); \
-} \
-void OPPROTO glue(op_iwmmxt_unpack, glue(S, ul_M0))(void) \
-{ \
- M0 = (((M0 >> SH0) & 0xffffffff) << 0); \
- env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(M0 >> 0); \
-} \
-void OPPROTO glue(op_iwmmxt_unpack, glue(S, sb_M0))(void) \
-{ \
- M0 = \
- (EXTEND8H((M0 >> SH0) & 0xff) << 0) | \
- (EXTEND8H((M0 >> SH1) & 0xff) << 16) | \
- (EXTEND8H((M0 >> SH2) & 0xff) << 32) | \
- (EXTEND8H((M0 >> SH3) & 0xff) << 48); \
- env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \
- NZBIT16(M0 >> 0, 0) | NZBIT16(M0 >> 16, 1) | \
- NZBIT16(M0 >> 32, 2) | NZBIT16(M0 >> 48, 3); \
-} \
-void OPPROTO glue(op_iwmmxt_unpack, glue(S, sw_M0))(void) \
-{ \
- M0 = \
- (EXTEND16((M0 >> SH0) & 0xffff) << 0) | \
- (EXTEND16((M0 >> SH2) & 0xffff) << 32); \
- env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \
- NZBIT32(M0 >> 0, 0) | NZBIT32(M0 >> 32, 1); \
-} \
-void OPPROTO glue(op_iwmmxt_unpack, glue(S, sl_M0))(void) \
-{ \
- M0 = EXTEND32((M0 >> SH0) & 0xffffffff); \
- env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(M0 >> 0); \
-}
-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) \
-void OPPROTO glue(op_iwmmxt_, glue(SUFF, b_M0_wRn))(void) \
-{ \
- M0 = \
- 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(M0 >> 0, 0) | NZBIT8(M0 >> 8, 1) | \
- NZBIT8(M0 >> 16, 2) | NZBIT8(M0 >> 24, 3) | \
- NZBIT8(M0 >> 32, 4) | NZBIT8(M0 >> 40, 5) | \
- NZBIT8(M0 >> 48, 6) | NZBIT8(M0 >> 56, 7); \
-} \
-void OPPROTO glue(op_iwmmxt_, glue(SUFF, w_M0_wRn))(void) \
-{ \
- M0 = 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(M0 >> 0, 0) | NZBIT16(M0 >> 16, 1) | \
- NZBIT16(M0 >> 32, 2) | NZBIT16(M0 >> 48, 3); \
-} \
-void OPPROTO glue(op_iwmmxt_, glue(SUFF, l_M0_wRn))(void) \
-{ \
- M0 = CMP(0, Tl, O, 0xffffffff) | \
- CMP(32, Tl, O, 0xffffffff); \
- env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \
- NZBIT32(M0 >> 0, 0) | NZBIT32(M0 >> 32, 1); \
-}
-#define CMP(SHR, TYPE, OPER, MASK) ((((TYPE) ((M0 >> SHR) & MASK) OPER \
- (TYPE) ((M1 >> 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) ((M0 >> SHR) & MASK) OPER \
- (TYPE) ((M1 >> SHR) & MASK)) ? M0 : M1) & ((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) ((M0 >> SHR) & MASK) \
- OPER (TYPE) ((M1 >> 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) ((M0 >> SHR) & MASK) \
- OPER (TYPE) ((M1 >> 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
-
-void OPPROTO op_iwmmxt_avgb_M0_wRn(void)
-{
-#define AVGB(SHR) ((( \
- ((M0 >> SHR) & 0xff) + ((M1 >> SHR) & 0xff) + PARAM2) >> 1) << SHR)
- M0 =
- 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((M0 >> 0) & 0xff), SIMD_ZBIT, 0) |
- SIMD8_SET(ZBIT8((M0 >> 8) & 0xff), SIMD_ZBIT, 1) |
- SIMD8_SET(ZBIT8((M0 >> 16) & 0xff), SIMD_ZBIT, 2) |
- SIMD8_SET(ZBIT8((M0 >> 24) & 0xff), SIMD_ZBIT, 3) |
- SIMD8_SET(ZBIT8((M0 >> 32) & 0xff), SIMD_ZBIT, 4) |
- SIMD8_SET(ZBIT8((M0 >> 40) & 0xff), SIMD_ZBIT, 5) |
- SIMD8_SET(ZBIT8((M0 >> 48) & 0xff), SIMD_ZBIT, 6) |
- SIMD8_SET(ZBIT8((M0 >> 56) & 0xff), SIMD_ZBIT, 7);
-#undef AVGB
-}
-
-void OPPROTO op_iwmmxt_avgw_M0_wRn(void)
-{
-#define AVGW(SHR) ((( \
- ((M0 >> SHR) & 0xffff) + ((M1 >> SHR) & 0xffff) + PARAM2) >> 1) << SHR)
- M0 = AVGW(0) | AVGW(16) | AVGW(32) | AVGW(48);
- env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
- SIMD16_SET(ZBIT16((M0 >> 0) & 0xffff), SIMD_ZBIT, 0) |
- SIMD16_SET(ZBIT16((M0 >> 16) & 0xffff), SIMD_ZBIT, 1) |
- SIMD16_SET(ZBIT16((M0 >> 32) & 0xffff), SIMD_ZBIT, 2) |
- SIMD16_SET(ZBIT16((M0 >> 48) & 0xffff), SIMD_ZBIT, 3);
-#undef AVGW
-}
-
-void OPPROTO op_iwmmxt_msadb_M0_wRn(void)
-{
- M0 = ((((M0 >> 0) & 0xffff) * ((M1 >> 0) & 0xffff) +
- ((M0 >> 16) & 0xffff) * ((M1 >> 16) & 0xffff)) & 0xffffffff) |
- ((((M0 >> 32) & 0xffff) * ((M1 >> 32) & 0xffff) +
- ((M0 >> 48) & 0xffff) * ((M1 >> 48) & 0xffff)) << 32);
-}
-
-void OPPROTO op_iwmmxt_align_M0_T0_wRn(void)
-{
- M0 >>= T0 << 3;
- M0 |= M1 << (64 - (T0 << 3));
-}
-
-void OPPROTO op_iwmmxt_insr_M0_T0_T1(void)
-{
- M0 &= ~((uint64_t) T1 << PARAM1);
- M0 |= (uint64_t) (T0 & T1) << PARAM1;
-}
-
-void OPPROTO op_iwmmxt_extrsb_T0_M0(void)
-{
- T0 = EXTEND8((M0 >> PARAM1) & 0xff);
-}
-
-void OPPROTO op_iwmmxt_extrsw_T0_M0(void)
-{
- T0 = EXTEND16((M0 >> PARAM1) & 0xffff);
-}
-
-void OPPROTO op_iwmmxt_extru_T0_M0_T1(void)
-{
- T0 = (M0 >> PARAM1) & T1;
-}
-
-void OPPROTO op_iwmmxt_bcstb_M0_T0(void)
-{
- T0 &= 0xff;
- M0 =
- ((uint64_t) T0 << 0) | ((uint64_t) T0 << 8) |
- ((uint64_t) T0 << 16) | ((uint64_t) T0 << 24) |
- ((uint64_t) T0 << 32) | ((uint64_t) T0 << 40) |
- ((uint64_t) T0 << 48) | ((uint64_t) T0 << 56);
-}
-
-void OPPROTO op_iwmmxt_bcstw_M0_T0(void)
-{
- T0 &= 0xffff;
- M0 =
- ((uint64_t) T0 << 0) | ((uint64_t) T0 << 16) |
- ((uint64_t) T0 << 32) | ((uint64_t) T0 << 48);
-}
-
-void OPPROTO op_iwmmxt_bcstl_M0_T0(void)
-{
- M0 = ((uint64_t) T0 << 0) | ((uint64_t) T0 << 32);
-}
-
-void OPPROTO op_iwmmxt_addcb_M0(void)
-{
- M0 =
- ((M0 >> 0) & 0xff) + ((M0 >> 8) & 0xff) +
- ((M0 >> 16) & 0xff) + ((M0 >> 24) & 0xff) +
- ((M0 >> 32) & 0xff) + ((M0 >> 40) & 0xff) +
- ((M0 >> 48) & 0xff) + ((M0 >> 56) & 0xff);
-}
-
-void OPPROTO op_iwmmxt_addcw_M0(void)
-{
- M0 =
- ((M0 >> 0) & 0xffff) + ((M0 >> 16) & 0xffff) +
- ((M0 >> 32) & 0xffff) + ((M0 >> 48) & 0xffff);
-}
-
-void OPPROTO op_iwmmxt_addcl_M0(void)
-{
- M0 = (M0 & 0xffffffff) + (M0 >> 32);
-}
-
-void OPPROTO op_iwmmxt_msbb_T0_M0(void)
-{
- T0 =
- ((M0 >> 7) & 0x01) | ((M0 >> 14) & 0x02) |
- ((M0 >> 21) & 0x04) | ((M0 >> 28) & 0x08) |
- ((M0 >> 35) & 0x10) | ((M0 >> 42) & 0x20) |
- ((M0 >> 49) & 0x40) | ((M0 >> 56) & 0x80);
-}
-
-void OPPROTO op_iwmmxt_msbw_T0_M0(void)
-{
- T0 =
- ((M0 >> 15) & 0x01) | ((M0 >> 30) & 0x02) |
- ((M0 >> 45) & 0x04) | ((M0 >> 52) & 0x08);
-}
-
-void OPPROTO op_iwmmxt_msbl_T0_M0(void)
-{
- T0 = ((M0 >> 31) & 0x01) | ((M0 >> 62) & 0x02);
-}
-
-void OPPROTO op_iwmmxt_srlw_M0_T0(void)
-{
- M0 =
- (((M0 & (0xffffll << 0)) >> T0) & (0xffffll << 0)) |
- (((M0 & (0xffffll << 16)) >> T0) & (0xffffll << 16)) |
- (((M0 & (0xffffll << 32)) >> T0) & (0xffffll << 32)) |
- (((M0 & (0xffffll << 48)) >> T0) & (0xffffll << 48));
- env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
- NZBIT16(M0 >> 0, 0) | NZBIT16(M0 >> 16, 1) |
- NZBIT16(M0 >> 32, 2) | NZBIT16(M0 >> 48, 3);
-}
-
-void OPPROTO op_iwmmxt_srll_M0_T0(void)
-{
- M0 =
- ((M0 & (0xffffffffll << 0)) >> T0) |
- ((M0 >> T0) & (0xffffffffll << 32));
- env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
- NZBIT32(M0 >> 0, 0) | NZBIT32(M0 >> 32, 1);
-}
-
-void OPPROTO op_iwmmxt_srlq_M0_T0(void)
-{
- M0 >>= T0;
- env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(M0);
-}
-
-void OPPROTO op_iwmmxt_sllw_M0_T0(void)
-{
- M0 =
- (((M0 & (0xffffll << 0)) << T0) & (0xffffll << 0)) |
- (((M0 & (0xffffll << 16)) << T0) & (0xffffll << 16)) |
- (((M0 & (0xffffll << 32)) << T0) & (0xffffll << 32)) |
- (((M0 & (0xffffll << 48)) << T0) & (0xffffll << 48));
- env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
- NZBIT16(M0 >> 0, 0) | NZBIT16(M0 >> 16, 1) |
- NZBIT16(M0 >> 32, 2) | NZBIT16(M0 >> 48, 3);
-}
-
-void OPPROTO op_iwmmxt_slll_M0_T0(void)
-{
- M0 =
- ((M0 << T0) & (0xffffffffll << 0)) |
- ((M0 & (0xffffffffll << 32)) << T0);
- env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
- NZBIT32(M0 >> 0, 0) | NZBIT32(M0 >> 32, 1);
-}
-
-void OPPROTO op_iwmmxt_sllq_M0_T0(void)
-{
- M0 <<= T0;
- env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(M0);
-}
-
-void OPPROTO op_iwmmxt_sraw_M0_T0(void)
-{
- M0 =
- (((EXTEND16(M0 >> 0) >> T0) & 0xffff) << 0) |
- (((EXTEND16(M0 >> 16) >> T0) & 0xffff) << 16) |
- (((EXTEND16(M0 >> 32) >> T0) & 0xffff) << 32) |
- (((EXTEND16(M0 >> 48) >> T0) & 0xffff) << 48);
- env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
- NZBIT16(M0 >> 0, 0) | NZBIT16(M0 >> 16, 1) |
- NZBIT16(M0 >> 32, 2) | NZBIT16(M0 >> 48, 3);
-}
-
-void OPPROTO op_iwmmxt_sral_M0_T0(void)
-{
- M0 =
- (((EXTEND32(M0 >> 0) >> T0) & 0xffffffff) << 0) |
- (((EXTEND32(M0 >> 32) >> T0) & 0xffffffff) << 32);
- env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
- NZBIT32(M0 >> 0, 0) | NZBIT32(M0 >> 32, 1);
-}
-
-void OPPROTO op_iwmmxt_sraq_M0_T0(void)
-{
- M0 = (int64_t) M0 >> T0;
- env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(M0);
-}
-
-void OPPROTO op_iwmmxt_rorw_M0_T0(void)
-{
- M0 =
- ((((M0 & (0xffffll << 0)) >> T0) |
- ((M0 & (0xffffll << 0)) << (16 - T0))) & (0xffffll << 0)) |
- ((((M0 & (0xffffll << 16)) >> T0) |
- ((M0 & (0xffffll << 16)) << (16 - T0))) & (0xffffll << 16)) |
- ((((M0 & (0xffffll << 32)) >> T0) |
- ((M0 & (0xffffll << 32)) << (16 - T0))) & (0xffffll << 32)) |
- ((((M0 & (0xffffll << 48)) >> T0) |
- ((M0 & (0xffffll << 48)) << (16 - T0))) & (0xffffll << 48));
- env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
- NZBIT16(M0 >> 0, 0) | NZBIT16(M0 >> 16, 1) |
- NZBIT16(M0 >> 32, 2) | NZBIT16(M0 >> 48, 3);
-}
-
-void OPPROTO op_iwmmxt_rorl_M0_T0(void)
-{
- M0 =
- ((M0 & (0xffffffffll << 0)) >> T0) |
- ((M0 >> T0) & (0xffffffffll << 32)) |
- ((M0 << (32 - T0)) & (0xffffffffll << 0)) |
- ((M0 & (0xffffffffll << 32)) << (32 - T0));
- env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
- NZBIT32(M0 >> 0, 0) | NZBIT32(M0 >> 32, 1);
-}
-
-void OPPROTO op_iwmmxt_rorq_M0_T0(void)
-{
- M0 = (M0 >> T0) | (M0 << (64 - T0));
- env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(M0);
-}
-
-void OPPROTO op_iwmmxt_shufh_M0_T0(void)
-{
- M0 =
- (((M0 >> ((T0 << 4) & 0x30)) & 0xffff) << 0) |
- (((M0 >> ((T0 << 2) & 0x30)) & 0xffff) << 16) |
- (((M0 >> ((T0 << 0) & 0x30)) & 0xffff) << 32) |
- (((M0 >> ((T0 >> 2) & 0x30)) & 0xffff) << 48);
- env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
- NZBIT16(M0 >> 0, 0) | NZBIT16(M0 >> 16, 1) |
- NZBIT16(M0 >> 32, 2) | NZBIT16(M0 >> 48, 3);
-}
-
-/* TODO: Unsigned-Saturation */
-void OPPROTO op_iwmmxt_packuw_M0_wRn(void)
-{
- M0 =
- (((M0 >> 0) & 0xff) << 0) | (((M0 >> 16) & 0xff) << 8) |
- (((M0 >> 32) & 0xff) << 16) | (((M0 >> 48) & 0xff) << 24) |
- (((M1 >> 0) & 0xff) << 32) | (((M1 >> 16) & 0xff) << 40) |
- (((M1 >> 32) & 0xff) << 48) | (((M1 >> 48) & 0xff) << 56);
- env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
- NZBIT8(M0 >> 0, 0) | NZBIT8(M0 >> 8, 1) |
- NZBIT8(M0 >> 16, 2) | NZBIT8(M0 >> 24, 3) |
- NZBIT8(M0 >> 32, 4) | NZBIT8(M0 >> 40, 5) |
- NZBIT8(M0 >> 48, 6) | NZBIT8(M0 >> 56, 7);
-}
-
-void OPPROTO op_iwmmxt_packul_M0_wRn(void)
-{
- M0 =
- (((M0 >> 0) & 0xffff) << 0) | (((M0 >> 32) & 0xffff) << 16) |
- (((M1 >> 0) & 0xffff) << 32) | (((M1 >> 32) & 0xffff) << 48);
- env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
- NZBIT16(M0 >> 0, 0) | NZBIT16(M0 >> 16, 1) |
- NZBIT16(M0 >> 32, 2) | NZBIT16(M0 >> 48, 3);
-}
-
-void OPPROTO op_iwmmxt_packuq_M0_wRn(void)
-{
- M0 = (M0 & 0xffffffff) | ((M1 & 0xffffffff) << 32);
- env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
- NZBIT32(M0 >> 0, 0) | NZBIT32(M0 >> 32, 1);
-}
-
-/* TODO: Signed-Saturation */
-void OPPROTO op_iwmmxt_packsw_M0_wRn(void)
-{
- M0 =
- (((M0 >> 0) & 0xff) << 0) | (((M0 >> 16) & 0xff) << 8) |
- (((M0 >> 32) & 0xff) << 16) | (((M0 >> 48) & 0xff) << 24) |
- (((M1 >> 0) & 0xff) << 32) | (((M1 >> 16) & 0xff) << 40) |
- (((M1 >> 32) & 0xff) << 48) | (((M1 >> 48) & 0xff) << 56);
- env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
- NZBIT8(M0 >> 0, 0) | NZBIT8(M0 >> 8, 1) |
- NZBIT8(M0 >> 16, 2) | NZBIT8(M0 >> 24, 3) |
- NZBIT8(M0 >> 32, 4) | NZBIT8(M0 >> 40, 5) |
- NZBIT8(M0 >> 48, 6) | NZBIT8(M0 >> 56, 7);
-}
-
-void OPPROTO op_iwmmxt_packsl_M0_wRn(void)
-{
- M0 =
- (((M0 >> 0) & 0xffff) << 0) | (((M0 >> 32) & 0xffff) << 16) |
- (((M1 >> 0) & 0xffff) << 32) | (((M1 >> 32) & 0xffff) << 48);
- env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
- NZBIT16(M0 >> 0, 0) | NZBIT16(M0 >> 16, 1) |
- NZBIT16(M0 >> 32, 2) | NZBIT16(M0 >> 48, 3);
-}
-
-void OPPROTO op_iwmmxt_packsq_M0_wRn(void)
-{
- M0 = (M0 & 0xffffffff) | ((M1 & 0xffffffff) << 32);
- env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
- NZBIT32(M0 >> 0, 0) | NZBIT32(M0 >> 32, 1);
-}
-
-void OPPROTO op_iwmmxt_muladdsl_M0_T0_T1(void)
-{
- M0 += EXTEND32(T0) * EXTEND32(T1);
-}
-
-void OPPROTO op_iwmmxt_muladdsw_M0_T0_T1(void)
-{
- M0 += EXTEND32(EXTEND16((T0 >> 0) & 0xffff) *
- EXTEND16((T1 >> 0) & 0xffff));
- M0 += EXTEND32(EXTEND16((T0 >> 16) & 0xffff) *
- EXTEND16((T1 >> 16) & 0xffff));
-}
-
-void OPPROTO op_iwmmxt_muladdswl_M0_T0_T1(void)
-{
- M0 += EXTEND32(EXTEND16(T0 & 0xffff) * EXTEND16(T1 & 0xffff));
-}
+/* iwMMXt support */
+#include "op_iwmmxt.c"
Added: trunk/src/host/qemu-neo1973/target-arm/op_iwmmxt.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-arm/op_iwmmxt.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/target-arm/op_iwmmxt.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,707 @@
+/*
+ * iwMMXt micro operations for XScale.
+ *
+ * Copyright (c) 2007 OpenedHand, Ltd.
+ * Written by Andrzej Zaborowski <andrew at openedhand.com>
+ *
+ * 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
+ */
+
+#define M1 env->iwmmxt.regs[PARAM1]
+
+/* 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))
+
+void OPPROTO op_iwmmxt_movl_T0_T1_wRn(void)
+{
+ T0 = M1 & ~(uint32_t) 0;
+ T1 = M1 >> 32;
+}
+
+void OPPROTO op_iwmmxt_movl_wRn_T0_T1(void)
+{
+ M1 = ((uint64_t) T1 << 32) | T0;
+}
+
+void OPPROTO op_iwmmxt_movq_M0_wRn(void)
+{
+ M0 = M1;
+}
+
+void OPPROTO op_iwmmxt_orq_M0_wRn(void)
+{
+ M0 |= M1;
+}
+
+void OPPROTO op_iwmmxt_andq_M0_wRn(void)
+{
+ M0 &= M1;
+}
+
+void OPPROTO op_iwmmxt_xorq_M0_wRn(void)
+{
+ M0 ^= M1;
+}
+
+void OPPROTO op_iwmmxt_maddsq_M0_wRn(void)
+{
+ M0 = ((
+ EXTEND16S((M0 >> 0) & 0xffff) * EXTEND16S((M1 >> 0) & 0xffff) +
+ EXTEND16S((M0 >> 16) & 0xffff) * EXTEND16S((M1 >> 16) & 0xffff)
+ ) & 0xffffffff) | ((uint64_t) (
+ EXTEND16S((M0 >> 32) & 0xffff) * EXTEND16S((M1 >> 32) & 0xffff) +
+ EXTEND16S((M0 >> 48) & 0xffff) * EXTEND16S((M1 >> 48) & 0xffff)
+ ) << 32);
+}
+
+void OPPROTO op_iwmmxt_madduq_M0_wRn(void)
+{
+ M0 = ((
+ ((M0 >> 0) & 0xffff) * ((M1 >> 0) & 0xffff) +
+ ((M0 >> 16) & 0xffff) * ((M1 >> 16) & 0xffff)
+ ) & 0xffffffff) | ((
+ ((M0 >> 32) & 0xffff) * ((M1 >> 32) & 0xffff) +
+ ((M0 >> 48) & 0xffff) * ((M1 >> 48) & 0xffff)
+ ) << 32);
+}
+
+void OPPROTO op_iwmmxt_sadb_M0_wRn(void)
+{
+#define abs(x) (((x) >= 0) ? x : -x)
+#define SADB(SHR) abs((int) ((M0 >> SHR) & 0xff) - (int) ((M1 >> SHR) & 0xff))
+ M0 =
+ SADB(0) + SADB(8) + SADB(16) + SADB(24) +
+ SADB(32) + SADB(40) + SADB(48) + SADB(56);
+#undef SADB
+}
+
+void OPPROTO op_iwmmxt_sadw_M0_wRn(void)
+{
+#define SADW(SHR) \
+ abs((int) ((M0 >> SHR) & 0xffff) - (int) ((M1 >> SHR) & 0xffff))
+ M0 = SADW(0) + SADW(16) + SADW(32) + SADW(48);
+#undef SADW
+}
+
+void OPPROTO op_iwmmxt_addl_M0_wRn(void)
+{
+ M0 += env->iwmmxt.regs[PARAM1] & 0xffffffff;
+}
+
+void OPPROTO op_iwmmxt_mulsw_M0_wRn(void)
+{
+#define MULS(SHR) ((uint64_t) ((( \
+ EXTEND16S((M0 >> SHR) & 0xffff) * EXTEND16S((M1 >> SHR) & 0xffff) \
+ ) >> PARAM2) & 0xffff) << SHR)
+ M0 = MULS(0) | MULS(16) | MULS(32) | MULS(48);
+#undef MULS
+}
+
+void OPPROTO op_iwmmxt_muluw_M0_wRn(void)
+{
+#define MULU(SHR) ((uint64_t) ((( \
+ ((M0 >> SHR) & 0xffff) * ((M1 >> SHR) & 0xffff) \
+ ) >> PARAM2) & 0xffff) << SHR)
+ M0 = MULU(0) | MULU(16) | MULU(32) | MULU(48);
+#undef MULU
+}
+
+void OPPROTO op_iwmmxt_macsw_M0_wRn(void)
+{
+#define MACS(SHR) ( \
+ EXTEND16((M0 >> SHR) & 0xffff) * EXTEND16S((M1 >> SHR) & 0xffff))
+ M0 = (int64_t) (MACS(0) + MACS(16) + MACS(32) + MACS(48));
+#undef MACS
+}
+
+void OPPROTO op_iwmmxt_macuw_M0_wRn(void)
+{
+#define MACU(SHR) ( \
+ (uint32_t) ((M0 >> SHR) & 0xffff) * \
+ (uint32_t) ((M1 >> SHR) & 0xffff))
+ M0 = MACU(0) + MACU(16) + MACU(32) + MACU(48);
+#undef MACU
+}
+
+void OPPROTO op_iwmmxt_addsq_M0_wRn(void)
+{
+ M0 = (int64_t) M0 + (int64_t) M1;
+}
+
+void OPPROTO op_iwmmxt_adduq_M0_wRn(void)
+{
+ M0 += M1;
+}
+
+void OPPROTO op_iwmmxt_movq_wRn_M0(void)
+{
+ M1 = M0;
+}
+
+void OPPROTO op_iwmmxt_movl_wCx_T0(void)
+{
+ env->iwmmxt.cregs[PARAM1] = T0;
+}
+
+void OPPROTO op_iwmmxt_movl_T0_wCx(void)
+{
+ T0 = env->iwmmxt.cregs[PARAM1];
+}
+
+void OPPROTO op_iwmmxt_movl_T1_wCx(void)
+{
+ T1 = env->iwmmxt.cregs[PARAM1];
+}
+
+void OPPROTO op_iwmmxt_set_mup(void)
+{
+ env->iwmmxt.cregs[ARM_IWMMXT_wCon] |= 2;
+}
+
+void OPPROTO op_iwmmxt_set_cup(void)
+{
+ env->iwmmxt.cregs[ARM_IWMMXT_wCon] |= 1;
+}
+
+void OPPROTO op_iwmmxt_setpsr_nz(void)
+{
+ env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
+ SIMD64_SET((M0 == 0), SIMD_ZBIT) |
+ SIMD64_SET((M0 & (1ULL << 63)), SIMD_NBIT);
+}
+
+void OPPROTO op_iwmmxt_negq_M0(void)
+{
+ M0 = ~M0;
+}
+
+#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) \
+void OPPROTO glue(op_iwmmxt_unpack, glue(S, b_M0_wRn))(void) \
+{ \
+ M0 = \
+ (((M0 >> SH0) & 0xff) << 0) | (((M1 >> SH0) & 0xff) << 8) | \
+ (((M0 >> SH1) & 0xff) << 16) | (((M1 >> SH1) & 0xff) << 24) | \
+ (((M0 >> SH2) & 0xff) << 32) | (((M1 >> SH2) & 0xff) << 40) | \
+ (((M0 >> SH3) & 0xff) << 48) | (((M1 >> SH3) & 0xff) << 56); \
+ env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \
+ NZBIT8(M0 >> 0, 0) | NZBIT8(M0 >> 8, 1) | \
+ NZBIT8(M0 >> 16, 2) | NZBIT8(M0 >> 24, 3) | \
+ NZBIT8(M0 >> 32, 4) | NZBIT8(M0 >> 40, 5) | \
+ NZBIT8(M0 >> 48, 6) | NZBIT8(M0 >> 56, 7); \
+} \
+void OPPROTO glue(op_iwmmxt_unpack, glue(S, w_M0_wRn))(void) \
+{ \
+ M0 = \
+ (((M0 >> SH0) & 0xffff) << 0) | \
+ (((M1 >> SH0) & 0xffff) << 16) | \
+ (((M0 >> SH2) & 0xffff) << 32) | \
+ (((M1 >> SH2) & 0xffff) << 48); \
+ env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \
+ NZBIT8(M0 >> 0, 0) | NZBIT8(M0 >> 16, 1) | \
+ NZBIT8(M0 >> 32, 2) | NZBIT8(M0 >> 48, 3); \
+} \
+void OPPROTO glue(op_iwmmxt_unpack, glue(S, l_M0_wRn))(void) \
+{ \
+ M0 = \
+ (((M0 >> SH0) & 0xffffffff) << 0) | \
+ (((M1 >> SH0) & 0xffffffff) << 32); \
+ env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \
+ NZBIT32(M0 >> 0, 0) | NZBIT32(M0 >> 32, 1); \
+} \
+void OPPROTO glue(op_iwmmxt_unpack, glue(S, ub_M0))(void) \
+{ \
+ M0 = \
+ (((M0 >> SH0) & 0xff) << 0) | \
+ (((M0 >> SH1) & 0xff) << 16) | \
+ (((M0 >> SH2) & 0xff) << 32) | \
+ (((M0 >> SH3) & 0xff) << 48); \
+ env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \
+ NZBIT16(M0 >> 0, 0) | NZBIT16(M0 >> 16, 1) | \
+ NZBIT16(M0 >> 32, 2) | NZBIT16(M0 >> 48, 3); \
+} \
+void OPPROTO glue(op_iwmmxt_unpack, glue(S, uw_M0))(void) \
+{ \
+ M0 = \
+ (((M0 >> SH0) & 0xffff) << 0) | \
+ (((M0 >> SH2) & 0xffff) << 32); \
+ env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \
+ NZBIT32(M0 >> 0, 0) | NZBIT32(M0 >> 32, 1); \
+} \
+void OPPROTO glue(op_iwmmxt_unpack, glue(S, ul_M0))(void) \
+{ \
+ M0 = (((M0 >> SH0) & 0xffffffff) << 0); \
+ env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(M0 >> 0); \
+} \
+void OPPROTO glue(op_iwmmxt_unpack, glue(S, sb_M0))(void) \
+{ \
+ M0 = \
+ ((uint64_t) EXTEND8H((M0 >> SH0) & 0xff) << 0) | \
+ ((uint64_t) EXTEND8H((M0 >> SH1) & 0xff) << 16) | \
+ ((uint64_t) EXTEND8H((M0 >> SH2) & 0xff) << 32) | \
+ ((uint64_t) EXTEND8H((M0 >> SH3) & 0xff) << 48); \
+ env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \
+ NZBIT16(M0 >> 0, 0) | NZBIT16(M0 >> 16, 1) | \
+ NZBIT16(M0 >> 32, 2) | NZBIT16(M0 >> 48, 3); \
+} \
+void OPPROTO glue(op_iwmmxt_unpack, glue(S, sw_M0))(void) \
+{ \
+ M0 = \
+ ((uint64_t) EXTEND16((M0 >> SH0) & 0xffff) << 0) | \
+ ((uint64_t) EXTEND16((M0 >> SH2) & 0xffff) << 32); \
+ env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \
+ NZBIT32(M0 >> 0, 0) | NZBIT32(M0 >> 32, 1); \
+} \
+void OPPROTO glue(op_iwmmxt_unpack, glue(S, sl_M0))(void) \
+{ \
+ M0 = EXTEND32((M0 >> SH0) & 0xffffffff); \
+ env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(M0 >> 0); \
+}
+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) \
+void OPPROTO glue(op_iwmmxt_, glue(SUFF, b_M0_wRn))(void) \
+{ \
+ M0 = \
+ 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(M0 >> 0, 0) | NZBIT8(M0 >> 8, 1) | \
+ NZBIT8(M0 >> 16, 2) | NZBIT8(M0 >> 24, 3) | \
+ NZBIT8(M0 >> 32, 4) | NZBIT8(M0 >> 40, 5) | \
+ NZBIT8(M0 >> 48, 6) | NZBIT8(M0 >> 56, 7); \
+} \
+void OPPROTO glue(op_iwmmxt_, glue(SUFF, w_M0_wRn))(void) \
+{ \
+ M0 = 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(M0 >> 0, 0) | NZBIT16(M0 >> 16, 1) | \
+ NZBIT16(M0 >> 32, 2) | NZBIT16(M0 >> 48, 3); \
+} \
+void OPPROTO glue(op_iwmmxt_, glue(SUFF, l_M0_wRn))(void) \
+{ \
+ M0 = CMP(0, Tl, O, 0xffffffff) | \
+ CMP(32, Tl, O, 0xffffffff); \
+ env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = \
+ NZBIT32(M0 >> 0, 0) | NZBIT32(M0 >> 32, 1); \
+}
+#define CMP(SHR, TYPE, OPER, MASK) ((((TYPE) ((M0 >> SHR) & MASK) OPER \
+ (TYPE) ((M1 >> 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) ((M0 >> SHR) & MASK) OPER \
+ (TYPE) ((M1 >> SHR) & MASK)) ? M0 : M1) & ((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) ((M0 >> SHR) & MASK) \
+ OPER (TYPE) ((M1 >> 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) ((M0 >> SHR) & MASK) \
+ OPER (TYPE) ((M1 >> 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
+
+void OPPROTO op_iwmmxt_avgb_M0_wRn(void)
+{
+#define AVGB(SHR) ((( \
+ ((M0 >> SHR) & 0xff) + ((M1 >> SHR) & 0xff) + PARAM2) >> 1) << SHR)
+ M0 =
+ 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((M0 >> 0) & 0xff), SIMD_ZBIT, 0) |
+ SIMD8_SET(ZBIT8((M0 >> 8) & 0xff), SIMD_ZBIT, 1) |
+ SIMD8_SET(ZBIT8((M0 >> 16) & 0xff), SIMD_ZBIT, 2) |
+ SIMD8_SET(ZBIT8((M0 >> 24) & 0xff), SIMD_ZBIT, 3) |
+ SIMD8_SET(ZBIT8((M0 >> 32) & 0xff), SIMD_ZBIT, 4) |
+ SIMD8_SET(ZBIT8((M0 >> 40) & 0xff), SIMD_ZBIT, 5) |
+ SIMD8_SET(ZBIT8((M0 >> 48) & 0xff), SIMD_ZBIT, 6) |
+ SIMD8_SET(ZBIT8((M0 >> 56) & 0xff), SIMD_ZBIT, 7);
+#undef AVGB
+}
+
+void OPPROTO op_iwmmxt_avgw_M0_wRn(void)
+{
+#define AVGW(SHR) ((( \
+ ((M0 >> SHR) & 0xffff) + ((M1 >> SHR) & 0xffff) + PARAM2) >> 1) << SHR)
+ M0 = AVGW(0) | AVGW(16) | AVGW(32) | AVGW(48);
+ env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
+ SIMD16_SET(ZBIT16((M0 >> 0) & 0xffff), SIMD_ZBIT, 0) |
+ SIMD16_SET(ZBIT16((M0 >> 16) & 0xffff), SIMD_ZBIT, 1) |
+ SIMD16_SET(ZBIT16((M0 >> 32) & 0xffff), SIMD_ZBIT, 2) |
+ SIMD16_SET(ZBIT16((M0 >> 48) & 0xffff), SIMD_ZBIT, 3);
+#undef AVGW
+}
+
+void OPPROTO op_iwmmxt_msadb_M0_wRn(void)
+{
+ M0 = ((((M0 >> 0) & 0xffff) * ((M1 >> 0) & 0xffff) +
+ ((M0 >> 16) & 0xffff) * ((M1 >> 16) & 0xffff)) & 0xffffffff) |
+ ((((M0 >> 32) & 0xffff) * ((M1 >> 32) & 0xffff) +
+ ((M0 >> 48) & 0xffff) * ((M1 >> 48) & 0xffff)) << 32);
+}
+
+void OPPROTO op_iwmmxt_align_M0_T0_wRn(void)
+{
+ M0 >>= T0 << 3;
+ M0 |= M1 << (64 - (T0 << 3));
+}
+
+void OPPROTO op_iwmmxt_insr_M0_T0_T1(void)
+{
+ M0 &= ~((uint64_t) T1 << PARAM1);
+ M0 |= (uint64_t) (T0 & T1) << PARAM1;
+}
+
+void OPPROTO op_iwmmxt_extrsb_T0_M0(void)
+{
+ T0 = EXTEND8((M0 >> PARAM1) & 0xff);
+}
+
+void OPPROTO op_iwmmxt_extrsw_T0_M0(void)
+{
+ T0 = EXTEND16((M0 >> PARAM1) & 0xffff);
+}
+
+void OPPROTO op_iwmmxt_extru_T0_M0_T1(void)
+{
+ T0 = (M0 >> PARAM1) & T1;
+}
+
+void OPPROTO op_iwmmxt_bcstb_M0_T0(void)
+{
+ T0 &= 0xff;
+ M0 =
+ ((uint64_t) T0 << 0) | ((uint64_t) T0 << 8) |
+ ((uint64_t) T0 << 16) | ((uint64_t) T0 << 24) |
+ ((uint64_t) T0 << 32) | ((uint64_t) T0 << 40) |
+ ((uint64_t) T0 << 48) | ((uint64_t) T0 << 56);
+}
+
+void OPPROTO op_iwmmxt_bcstw_M0_T0(void)
+{
+ T0 &= 0xffff;
+ M0 =
+ ((uint64_t) T0 << 0) | ((uint64_t) T0 << 16) |
+ ((uint64_t) T0 << 32) | ((uint64_t) T0 << 48);
+}
+
+void OPPROTO op_iwmmxt_bcstl_M0_T0(void)
+{
+ M0 = ((uint64_t) T0 << 0) | ((uint64_t) T0 << 32);
+}
+
+void OPPROTO op_iwmmxt_addcb_M0(void)
+{
+ M0 =
+ ((M0 >> 0) & 0xff) + ((M0 >> 8) & 0xff) +
+ ((M0 >> 16) & 0xff) + ((M0 >> 24) & 0xff) +
+ ((M0 >> 32) & 0xff) + ((M0 >> 40) & 0xff) +
+ ((M0 >> 48) & 0xff) + ((M0 >> 56) & 0xff);
+}
+
+void OPPROTO op_iwmmxt_addcw_M0(void)
+{
+ M0 =
+ ((M0 >> 0) & 0xffff) + ((M0 >> 16) & 0xffff) +
+ ((M0 >> 32) & 0xffff) + ((M0 >> 48) & 0xffff);
+}
+
+void OPPROTO op_iwmmxt_addcl_M0(void)
+{
+ M0 = (M0 & 0xffffffff) + (M0 >> 32);
+}
+
+void OPPROTO op_iwmmxt_msbb_T0_M0(void)
+{
+ T0 =
+ ((M0 >> 7) & 0x01) | ((M0 >> 14) & 0x02) |
+ ((M0 >> 21) & 0x04) | ((M0 >> 28) & 0x08) |
+ ((M0 >> 35) & 0x10) | ((M0 >> 42) & 0x20) |
+ ((M0 >> 49) & 0x40) | ((M0 >> 56) & 0x80);
+}
+
+void OPPROTO op_iwmmxt_msbw_T0_M0(void)
+{
+ T0 =
+ ((M0 >> 15) & 0x01) | ((M0 >> 30) & 0x02) |
+ ((M0 >> 45) & 0x04) | ((M0 >> 52) & 0x08);
+}
+
+void OPPROTO op_iwmmxt_msbl_T0_M0(void)
+{
+ T0 = ((M0 >> 31) & 0x01) | ((M0 >> 62) & 0x02);
+}
+
+void OPPROTO op_iwmmxt_srlw_M0_T0(void)
+{
+ M0 =
+ (((M0 & (0xffffll << 0)) >> T0) & (0xffffll << 0)) |
+ (((M0 & (0xffffll << 16)) >> T0) & (0xffffll << 16)) |
+ (((M0 & (0xffffll << 32)) >> T0) & (0xffffll << 32)) |
+ (((M0 & (0xffffll << 48)) >> T0) & (0xffffll << 48));
+ env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
+ NZBIT16(M0 >> 0, 0) | NZBIT16(M0 >> 16, 1) |
+ NZBIT16(M0 >> 32, 2) | NZBIT16(M0 >> 48, 3);
+}
+
+void OPPROTO op_iwmmxt_srll_M0_T0(void)
+{
+ M0 =
+ ((M0 & (0xffffffffll << 0)) >> T0) |
+ ((M0 >> T0) & (0xffffffffll << 32));
+ env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
+ NZBIT32(M0 >> 0, 0) | NZBIT32(M0 >> 32, 1);
+}
+
+void OPPROTO op_iwmmxt_srlq_M0_T0(void)
+{
+ M0 >>= T0;
+ env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(M0);
+}
+
+void OPPROTO op_iwmmxt_sllw_M0_T0(void)
+{
+ M0 =
+ (((M0 & (0xffffll << 0)) << T0) & (0xffffll << 0)) |
+ (((M0 & (0xffffll << 16)) << T0) & (0xffffll << 16)) |
+ (((M0 & (0xffffll << 32)) << T0) & (0xffffll << 32)) |
+ (((M0 & (0xffffll << 48)) << T0) & (0xffffll << 48));
+ env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
+ NZBIT16(M0 >> 0, 0) | NZBIT16(M0 >> 16, 1) |
+ NZBIT16(M0 >> 32, 2) | NZBIT16(M0 >> 48, 3);
+}
+
+void OPPROTO op_iwmmxt_slll_M0_T0(void)
+{
+ M0 =
+ ((M0 << T0) & (0xffffffffll << 0)) |
+ ((M0 & (0xffffffffll << 32)) << T0);
+ env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
+ NZBIT32(M0 >> 0, 0) | NZBIT32(M0 >> 32, 1);
+}
+
+void OPPROTO op_iwmmxt_sllq_M0_T0(void)
+{
+ M0 <<= T0;
+ env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(M0);
+}
+
+void OPPROTO op_iwmmxt_sraw_M0_T0(void)
+{
+ M0 =
+ ((uint64_t) ((EXTEND16(M0 >> 0) >> T0) & 0xffff) << 0) |
+ ((uint64_t) ((EXTEND16(M0 >> 16) >> T0) & 0xffff) << 16) |
+ ((uint64_t) ((EXTEND16(M0 >> 32) >> T0) & 0xffff) << 32) |
+ ((uint64_t) ((EXTEND16(M0 >> 48) >> T0) & 0xffff) << 48);
+ env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
+ NZBIT16(M0 >> 0, 0) | NZBIT16(M0 >> 16, 1) |
+ NZBIT16(M0 >> 32, 2) | NZBIT16(M0 >> 48, 3);
+}
+
+void OPPROTO op_iwmmxt_sral_M0_T0(void)
+{
+ M0 =
+ (((EXTEND32(M0 >> 0) >> T0) & 0xffffffff) << 0) |
+ (((EXTEND32(M0 >> 32) >> T0) & 0xffffffff) << 32);
+ env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
+ NZBIT32(M0 >> 0, 0) | NZBIT32(M0 >> 32, 1);
+}
+
+void OPPROTO op_iwmmxt_sraq_M0_T0(void)
+{
+ M0 = (int64_t) M0 >> T0;
+ env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(M0);
+}
+
+void OPPROTO op_iwmmxt_rorw_M0_T0(void)
+{
+ M0 =
+ ((((M0 & (0xffffll << 0)) >> T0) |
+ ((M0 & (0xffffll << 0)) << (16 - T0))) & (0xffffll << 0)) |
+ ((((M0 & (0xffffll << 16)) >> T0) |
+ ((M0 & (0xffffll << 16)) << (16 - T0))) & (0xffffll << 16)) |
+ ((((M0 & (0xffffll << 32)) >> T0) |
+ ((M0 & (0xffffll << 32)) << (16 - T0))) & (0xffffll << 32)) |
+ ((((M0 & (0xffffll << 48)) >> T0) |
+ ((M0 & (0xffffll << 48)) << (16 - T0))) & (0xffffll << 48));
+ env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
+ NZBIT16(M0 >> 0, 0) | NZBIT16(M0 >> 16, 1) |
+ NZBIT16(M0 >> 32, 2) | NZBIT16(M0 >> 48, 3);
+}
+
+void OPPROTO op_iwmmxt_rorl_M0_T0(void)
+{
+ M0 =
+ ((M0 & (0xffffffffll << 0)) >> T0) |
+ ((M0 >> T0) & (0xffffffffll << 32)) |
+ ((M0 << (32 - T0)) & (0xffffffffll << 0)) |
+ ((M0 & (0xffffffffll << 32)) << (32 - T0));
+ env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
+ NZBIT32(M0 >> 0, 0) | NZBIT32(M0 >> 32, 1);
+}
+
+void OPPROTO op_iwmmxt_rorq_M0_T0(void)
+{
+ M0 = (M0 >> T0) | (M0 << (64 - T0));
+ env->iwmmxt.cregs[ARM_IWMMXT_wCASF] = NZBIT64(M0);
+}
+
+void OPPROTO op_iwmmxt_shufh_M0_T0(void)
+{
+ M0 =
+ (((M0 >> ((T0 << 4) & 0x30)) & 0xffff) << 0) |
+ (((M0 >> ((T0 << 2) & 0x30)) & 0xffff) << 16) |
+ (((M0 >> ((T0 << 0) & 0x30)) & 0xffff) << 32) |
+ (((M0 >> ((T0 >> 2) & 0x30)) & 0xffff) << 48);
+ env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
+ NZBIT16(M0 >> 0, 0) | NZBIT16(M0 >> 16, 1) |
+ NZBIT16(M0 >> 32, 2) | NZBIT16(M0 >> 48, 3);
+}
+
+/* TODO: Unsigned-Saturation */
+void OPPROTO op_iwmmxt_packuw_M0_wRn(void)
+{
+ M0 =
+ (((M0 >> 0) & 0xff) << 0) | (((M0 >> 16) & 0xff) << 8) |
+ (((M0 >> 32) & 0xff) << 16) | (((M0 >> 48) & 0xff) << 24) |
+ (((M1 >> 0) & 0xff) << 32) | (((M1 >> 16) & 0xff) << 40) |
+ (((M1 >> 32) & 0xff) << 48) | (((M1 >> 48) & 0xff) << 56);
+ env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
+ NZBIT8(M0 >> 0, 0) | NZBIT8(M0 >> 8, 1) |
+ NZBIT8(M0 >> 16, 2) | NZBIT8(M0 >> 24, 3) |
+ NZBIT8(M0 >> 32, 4) | NZBIT8(M0 >> 40, 5) |
+ NZBIT8(M0 >> 48, 6) | NZBIT8(M0 >> 56, 7);
+}
+
+void OPPROTO op_iwmmxt_packul_M0_wRn(void)
+{
+ M0 =
+ (((M0 >> 0) & 0xffff) << 0) | (((M0 >> 32) & 0xffff) << 16) |
+ (((M1 >> 0) & 0xffff) << 32) | (((M1 >> 32) & 0xffff) << 48);
+ env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
+ NZBIT16(M0 >> 0, 0) | NZBIT16(M0 >> 16, 1) |
+ NZBIT16(M0 >> 32, 2) | NZBIT16(M0 >> 48, 3);
+}
+
+void OPPROTO op_iwmmxt_packuq_M0_wRn(void)
+{
+ M0 = (M0 & 0xffffffff) | ((M1 & 0xffffffff) << 32);
+ env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
+ NZBIT32(M0 >> 0, 0) | NZBIT32(M0 >> 32, 1);
+}
+
+/* TODO: Signed-Saturation */
+void OPPROTO op_iwmmxt_packsw_M0_wRn(void)
+{
+ M0 =
+ (((M0 >> 0) & 0xff) << 0) | (((M0 >> 16) & 0xff) << 8) |
+ (((M0 >> 32) & 0xff) << 16) | (((M0 >> 48) & 0xff) << 24) |
+ (((M1 >> 0) & 0xff) << 32) | (((M1 >> 16) & 0xff) << 40) |
+ (((M1 >> 32) & 0xff) << 48) | (((M1 >> 48) & 0xff) << 56);
+ env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
+ NZBIT8(M0 >> 0, 0) | NZBIT8(M0 >> 8, 1) |
+ NZBIT8(M0 >> 16, 2) | NZBIT8(M0 >> 24, 3) |
+ NZBIT8(M0 >> 32, 4) | NZBIT8(M0 >> 40, 5) |
+ NZBIT8(M0 >> 48, 6) | NZBIT8(M0 >> 56, 7);
+}
+
+void OPPROTO op_iwmmxt_packsl_M0_wRn(void)
+{
+ M0 =
+ (((M0 >> 0) & 0xffff) << 0) | (((M0 >> 32) & 0xffff) << 16) |
+ (((M1 >> 0) & 0xffff) << 32) | (((M1 >> 32) & 0xffff) << 48);
+ env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
+ NZBIT16(M0 >> 0, 0) | NZBIT16(M0 >> 16, 1) |
+ NZBIT16(M0 >> 32, 2) | NZBIT16(M0 >> 48, 3);
+}
+
+void OPPROTO op_iwmmxt_packsq_M0_wRn(void)
+{
+ M0 = (M0 & 0xffffffff) | ((M1 & 0xffffffff) << 32);
+ env->iwmmxt.cregs[ARM_IWMMXT_wCASF] =
+ NZBIT32(M0 >> 0, 0) | NZBIT32(M0 >> 32, 1);
+}
+
+void OPPROTO op_iwmmxt_muladdsl_M0_T0_T1(void)
+{
+ M0 += (int32_t) EXTEND32(T0) * (int32_t) EXTEND32(T1);
+}
+
+void OPPROTO op_iwmmxt_muladdsw_M0_T0_T1(void)
+{
+ M0 += EXTEND32(EXTEND16S((T0 >> 0) & 0xffff) *
+ EXTEND16S((T1 >> 0) & 0xffff));
+ M0 += EXTEND32(EXTEND16S((T0 >> 16) & 0xffff) *
+ EXTEND16S((T1 >> 16) & 0xffff));
+}
+
+void OPPROTO op_iwmmxt_muladdswl_M0_T0_T1(void)
+{
+ M0 += EXTEND32(EXTEND16S(T0 & 0xffff) *
+ EXTEND16S(T1 & 0xffff));
+}
Modified: trunk/src/host/qemu-neo1973/target-arm/translate.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-arm/translate.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/target-arm/translate.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -46,6 +46,7 @@
struct TranslationBlock *tb;
int singlestep_enabled;
int thumb;
+ int is_mem;
#if !defined(CONFIG_USER_ONLY)
int user;
#endif
@@ -291,6 +292,7 @@
#define gen_ldst(name, s) gen_op_##name##_raw()
#else
#define gen_ldst(name, s) do { \
+ s->is_mem = 1; \
if (IS_USER(s)) \
gen_op_##name##_user(); \
else \
@@ -392,9 +394,9 @@
if (insn & (1 << 22)) {
/* immediate */
val = (insn & 0xf) | ((insn >> 4) & 0xf0);
- val += extra;
if (!(insn & (1 << 23)))
val = -val;
+ val += extra;
if (val != 0)
gen_op_addl_T1_im(val);
} else {
@@ -501,7 +503,7 @@
rd = (insn >> 16) & 0xf;
gen_movl_T1_reg(s, rd);
- offset = (insn & 0xff) << ((insn >> 6) & 4);
+ offset = (insn & 0xff) << ((insn >> 7) & 2);
if (insn & (1 << 24)) {
/* Pre indexed */
if (insn & (1 << 23))
@@ -548,9 +550,6 @@
int rd, wrd;
int rdhi, rdlo, rd0, rd1, i;
- if (!arm_feature(env, ARM_FEATURE_IWMMXT))
- return 1;
-
if ((insn & 0x0e000e00) == 0x0c000000) {
if ((insn & 0x0fe00ff0) == 0x0c400000) {
wrd = insn & 0xf;
@@ -1482,32 +1481,110 @@
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;
+
+ 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;
+
+ switch ((insn >> 16) & 0xf) {
+ case 0x0: /* MIA */
+ gen_op_movl_TN_reg[0][rd0]();
+ gen_op_movl_TN_reg[1][rd1]();
+ gen_op_iwmmxt_muladdsl_M0_T0_T1();
+ break;
+ case 0x8: /* MIAPH */
+ gen_op_movl_TN_reg[0][rd0]();
+ gen_op_movl_TN_reg[1][rd1]();
+ gen_op_iwmmxt_muladdsw_M0_T0_T1();
+ break;
+ case 0xc: /* MIABB */
+ case 0xd: /* MIABT */
+ case 0xe: /* MIATB */
+ case 0xf: /* MIATT */
+ gen_op_movl_TN_reg[1][rd0]();
+ if (insn & (1 << 16))
+ gen_op_shrl_T1_im(16);
+ gen_op_movl_T0_T1();
+ gen_op_movl_TN_reg[1][rd1]();
+ if (insn & (1 << 17))
+ gen_op_shrl_T1_im(16);
+ gen_op_iwmmxt_muladdswl_M0_T0_T1();
+ break;
+ default:
+ return 1;
+ }
+
+ 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 */
+ gen_op_iwmmxt_movl_T0_T1_wRn(acc);
+ gen_op_movl_reg_TN[0][rdlo]();
+ gen_op_movl_T0_im((1 << (40 - 32)) - 1);
+ gen_op_andl_T0_T1();
+ gen_op_movl_reg_TN[0][rdhi]();
+ } else { /* MAR */
+ gen_op_movl_TN_reg[0][rdlo]();
+ gen_op_movl_TN_reg[1][rdhi]();
+ gen_op_iwmmxt_movl_wRn_T0_T1(acc);
+ }
+ return 0;
+ }
+
+ return 1;
+}
+
/* Disassemble system coprocessor instruction. Return nonzero if
instruction is not defined. */
-static int disas_cp_insn(DisasContext *s, uint32_t insn)
+static int disas_cp_insn(CPUState *env, DisasContext *s, uint32_t insn)
{
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_op_movl_T0_im((uint32_t) s->pc);
+ gen_op_movl_reg_TN[0][15]();
gen_op_movl_T0_cp(insn);
gen_movl_reg_T0(s, rd);
} else {
+ if (!env->cp[cp].cp_write)
+ return 1;
gen_op_movl_T0_im((uint32_t) s->pc);
gen_op_movl_reg_TN[0][15]();
gen_movl_T0_reg(s, rd);
gen_op_movl_cp_T0(insn);
- s->is_jmp = DISAS_UPDATE;
}
-
return 0;
}
/* Disassemble system coprocessor (cp15) instruction. Return nonzero if
instruction is not defined. */
-static int disas_cp15_insn(DisasContext *s, uint32_t insn)
+static int disas_cp15_insn(CPUState *env, DisasContext *s, uint32_t insn)
{
uint32_t rd;
@@ -1533,10 +1610,13 @@
} else {
gen_movl_T0_reg(s, rd);
gen_op_movl_cp15_T0(insn);
+ /* 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);
}
-#if 0
- gen_lookup_tb(s);
-#endif
return 0;
}
@@ -2552,6 +2632,7 @@
}
} else {
int address_offset;
+ int load;
/* Misc load/store */
rn = (insn >> 16) & 0xf;
rd = (insn >> 12) & 0xf;
@@ -2573,7 +2654,7 @@
gen_ldst(ldsw, s);
break;
}
- gen_movl_reg_T0(s, rd);
+ load = 1;
} else if (sh & 2) {
/* doubleword */
if (sh & 1) {
@@ -2583,20 +2664,27 @@
gen_op_addl_T1_im(4);
gen_movl_T0_reg(s, rd + 1);
gen_ldst(stl, s);
+ load = 0;
} else {
/* load */
gen_ldst(ldl, s);
gen_movl_reg_T0(s, rd);
gen_op_addl_T1_im(4);
gen_ldst(ldl, s);
- gen_movl_reg_T0(s, rd + 1);
+ rd++;
+ load = 1;
}
address_offset = -4;
} else {
/* store */
gen_movl_T0_reg(s, rd);
gen_ldst(stw, 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);
gen_movl_reg_T1(s, rn);
@@ -2605,6 +2693,10 @@
gen_op_addl_T1_im(address_offset);
gen_movl_reg_T1(s, rn);
}
+ if (load) {
+ /* Complete the load. */
+ gen_movl_reg_T0(s, rd);
+ }
}
break;
case 0x4:
@@ -2629,6 +2721,7 @@
gen_add_data_offset(s, insn);
if (insn & (1 << 20)) {
/* load */
+ s->is_mem = 1;
#if defined(CONFIG_USER_ONLY)
if (insn & (1 << 22))
gen_op_ldub_raw();
@@ -2647,10 +2740,6 @@
gen_op_ldl_kernel();
}
#endif
- if (rd == 15)
- gen_bx(s);
- else
- gen_movl_reg_T0(s, rd);
} else {
/* store */
gen_movl_T0_reg(s, rd);
@@ -2679,6 +2768,13 @@
} else if (insn & (1 << 21))
gen_movl_reg_T1(s, rn); {
}
+ if (insn & (1 << 20)) {
+ /* Complete the load. */
+ if (rd == 15)
+ gen_bx(s);
+ else
+ gen_movl_reg_T0(s, rd);
+ }
break;
case 0x08:
case 0x09:
@@ -2816,12 +2912,18 @@
goto illegal_op;
switch (op1) {
case 0 ... 1:
- if (disas_iwmmxt_insn(env, s, insn))
+ if (arm_feature(env, ARM_FEATURE_IWMMXT)) {
+ if (disas_iwmmxt_insn(env, s, insn))
+ goto illegal_op;
+ } else if (arm_feature(env, ARM_FEATURE_XSCALE)) {
+ if (disas_dsp_insn(env, s, insn))
+ goto illegal_op;
+ } else
goto illegal_op;
break;
case 2 ... 9:
case 12 ... 14:
- if (disas_cp_insn(s, insn))
+ if (disas_cp_insn (env, s, insn))
goto illegal_op;
break;
case 10:
@@ -2830,7 +2932,7 @@
goto illegal_op;
break;
case 15:
- if (disas_cp15_insn (s, insn))
+ if (disas_cp15_insn (env, s, insn))
goto illegal_op;
break;
default:
@@ -3438,6 +3540,7 @@
dc->singlestep_enabled = env->singlestep_enabled;
dc->condjmp = 0;
dc->thumb = env->thumb;
+ dc->is_mem = 0;
#if !defined(CONFIG_USER_ONLY)
dc->user = (env->uncached_cpsr & 0x1f) == ARM_CPU_MODE_USR;
#endif
@@ -3476,6 +3579,12 @@
gen_set_label(dc->condlabel);
dc->condjmp = 0;
}
+ /* Terminate the TB on memory ops if watchpoints are present. */
+ /* FIXME: This should be replacd by the deterministic execution
+ * IRQ raising bits. */
+ if (dc->is_mem && env->nb_watchpoints)
+ break;
+
/* Translation stops when a conditional branch is enoutered.
* Otherwise the subsequent code could get translated several times.
* Also stop translation when a page boundary is reached. This
@@ -3587,8 +3696,8 @@
cpu_fprintf(f, " ");
}
psr = cpsr_read(env);
- cpu_fprintf(f, "PSR=%08x %c%c%c%c %c %s%d %x\n",
- psr,
+ 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' : '-',
Modified: trunk/src/host/qemu-neo1973/target-i386/cpu.h
===================================================================
--- trunk/src/host/qemu-neo1973/target-i386/cpu.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/target-i386/cpu.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -46,7 +46,7 @@
#include "softfloat.h"
-#if defined(__i386__) && !defined(CONFIG_SOFTMMU)
+#if defined(__i386__) && !defined(CONFIG_SOFTMMU) && !defined(__APPLE__)
#define USE_CODE_COPY
#endif
@@ -515,6 +515,7 @@
uint32_t smbase;
int interrupt_request;
int user_mode_only; /* user mode only simulation */
+ int old_exception; /* exception in flight */
CPU_COMMON
@@ -529,6 +530,7 @@
uint32_t cpuid_xlevel;
uint32_t cpuid_model[12];
uint32_t cpuid_ext2_features;
+ uint32_t cpuid_apic_id;
#ifdef USE_KQEMU
int kqemu_enabled;
@@ -628,8 +630,7 @@
/* you can call this signal handler from your SIGBUS and SIGSEGV
signal handlers to inform the virtual CPU of exceptions. non zero
is returned if the signal was handled by the virtual CPU. */
-struct siginfo;
-int cpu_x86_signal_handler(int host_signum, struct siginfo *info,
+int cpu_x86_signal_handler(int host_signum, void *pinfo,
void *puc);
void cpu_x86_set_a20(CPUX86State *env, int a20_state);
Modified: trunk/src/host/qemu-neo1973/target-i386/helper.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-i386/helper.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/target-i386/helper.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -977,7 +977,7 @@
cpu_x86_set_cpl(env, 0);
cpu_x86_load_seg_cache(env, R_CS, selector & 0xfffc,
0, 0xffffffff,
- DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
+ DESC_G_MASK | DESC_P_MASK |
DESC_S_MASK |
DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | DESC_L_MASK);
cpu_x86_load_seg_cache(env, R_SS, (selector + 8) & 0xfffc,
@@ -1028,7 +1028,7 @@
if (dflag == 2) {
cpu_x86_load_seg_cache(env, R_CS, (selector + 16) | 3,
0, 0xffffffff,
- DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
+ DESC_G_MASK | DESC_P_MASK |
DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK |
DESC_L_MASK);
@@ -1193,6 +1193,40 @@
}
/*
+ * Check nested exceptions and change to double or triple fault if
+ * needed. It should only be called, if this is not an interrupt.
+ * Returns the new exception number.
+ */
+int check_exception(int intno, int *error_code)
+{
+ char first_contributory = env->old_exception == 0 ||
+ (env->old_exception >= 10 &&
+ env->old_exception <= 13);
+ char second_contributory = intno == 0 ||
+ (intno >= 10 && intno <= 13);
+
+ if (loglevel & CPU_LOG_INT)
+ fprintf(logfile, "check_exception old: %x new %x\n",
+ env->old_exception, intno);
+
+ if (env->old_exception == EXCP08_DBLE)
+ cpu_abort(env, "triple fault");
+
+ if ((first_contributory && second_contributory)
+ || (env->old_exception == EXCP0E_PAGE &&
+ (second_contributory || (intno == EXCP0E_PAGE)))) {
+ intno = EXCP08_DBLE;
+ *error_code = 0;
+ }
+
+ if (second_contributory || (intno == EXCP0E_PAGE) ||
+ (intno == EXCP08_DBLE))
+ env->old_exception = intno;
+
+ return intno;
+}
+
+/*
* Signal an interruption. It is executed in the main CPU loop.
* is_int is TRUE if coming from the int instruction. next_eip is the
* EIP value AFTER the interrupt instruction. It is only relevant if
@@ -1201,6 +1235,9 @@
void raise_interrupt(int intno, int is_int, int error_code,
int next_eip_addend)
{
+ if (!is_int)
+ intno = check_exception(intno, &error_code);
+
env->exception_index = intno;
env->error_code = error_code;
env->exception_is_int = is_int;
@@ -1211,6 +1248,8 @@
/* same as raise_exception_err, but do not restore global registers */
static void raise_exception_err_norestore(int exception_index, int error_code)
{
+ exception_index = check_exception(exception_index, &error_code);
+
env->exception_index = exception_index;
env->error_code = error_code;
env->exception_is_int = 0;
@@ -1614,7 +1653,7 @@
break;
case 1:
EAX = env->cpuid_version;
- EBX = 8 << 8; /* CLFLUSH size in quad words, Linux wants it. */
+ EBX = (env->cpuid_apic_id << 24) | 8 << 8; /* CLFLUSH size in quad words, Linux wants it. */
ECX = env->cpuid_ext_features;
EDX = env->cpuid_features;
break;
@@ -1825,8 +1864,11 @@
raise_exception_err(EXCP0B_NOSEG, selector & 0xfffc);
#ifdef TARGET_X86_64
if (env->hflags & HF_LMA_MASK) {
- uint32_t e3;
+ uint32_t e3, e4;
e3 = ldl_kernel(ptr + 8);
+ e4 = ldl_kernel(ptr + 12);
+ if ((e4 >> DESC_TYPE_SHIFT) & 0xf)
+ raise_exception_err(EXCP0D_GPF, selector & 0xfffc);
load_seg_cache_raw_dt(&env->tr, e1, e2);
env->tr.base |= (target_ulong)e3 << 32;
} else
@@ -2422,12 +2464,14 @@
if ((new_ss & 0xfffc) == 0) {
#ifdef TARGET_X86_64
/* NULL ss is allowed in long mode if cpl != 3*/
+ /* XXX: test CS64 ? */
if ((env->hflags & HF_LMA_MASK) && rpl != 3) {
cpu_x86_load_seg_cache(env, R_SS, new_ss,
0, 0xffffffff,
DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
DESC_S_MASK | (rpl << DESC_DPL_SHIFT) |
DESC_W_MASK | DESC_A_MASK);
+ ss_e2 = DESC_B_MASK; /* XXX: should not be needed ? */
} else
#endif
{
@@ -3095,30 +3139,51 @@
CPU86_LDouble dblq, fpsrcop, fptemp;
CPU86_LDoubleU fpsrcop1, fptemp1;
int expdif;
- int q;
+ signed long long int q;
+ if (isinf(ST0) || isnan(ST0) || isnan(ST1) || (ST1 == 0.0)) {
+ ST0 = 0.0 / 0.0; /* NaN */
+ env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
+ return;
+ }
+
fpsrcop = ST0;
fptemp = ST1;
fpsrcop1.d = fpsrcop;
fptemp1.d = fptemp;
expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
+
+ if (expdif < 0) {
+ /* optimisation? taken from the AMD docs */
+ env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
+ /* ST0 is unchanged */
+ return;
+ }
+
if (expdif < 53) {
dblq = fpsrcop / fptemp;
- dblq = (dblq < 0.0)? ceil(dblq): floor(dblq);
- ST0 = fpsrcop - fptemp*dblq;
- q = (int)dblq; /* cutting off top bits is assumed here */
+ /* round dblq towards nearest integer */
+ dblq = rint(dblq);
+ ST0 = fpsrcop - fptemp * dblq;
+
+ /* convert dblq to q by truncating towards zero */
+ if (dblq < 0.0)
+ q = (signed long long int)(-dblq);
+ else
+ q = (signed long long int)dblq;
+
env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
- /* (C0,C1,C3) <-- (q2,q1,q0) */
- env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */
- env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */
- env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */
+ /* (C0,C3,C1) <-- (q2,q1,q0) */
+ env->fpus |= (q & 0x4) << (8 - 2); /* (C0) <-- q2 */
+ env->fpus |= (q & 0x2) << (14 - 1); /* (C3) <-- q1 */
+ env->fpus |= (q & 0x1) << (9 - 0); /* (C1) <-- q0 */
} else {
env->fpus |= 0x400; /* C2 <-- 1 */
- fptemp = pow(2.0, expdif-50);
+ fptemp = pow(2.0, expdif - 50);
fpsrcop = (ST0 / ST1) / fptemp;
- /* fpsrcop = integer obtained by rounding to the nearest */
- fpsrcop = (fpsrcop-floor(fpsrcop) < ceil(fpsrcop)-fpsrcop)?
- floor(fpsrcop): ceil(fpsrcop);
+ /* fpsrcop = integer obtained by chopping */
+ fpsrcop = (fpsrcop < 0.0) ?
+ -(floor(fabs(fpsrcop))) : floor(fpsrcop);
ST0 -= (ST1 * fpsrcop * fptemp);
}
}
@@ -3128,30 +3193,52 @@
CPU86_LDouble dblq, fpsrcop, fptemp;
CPU86_LDoubleU fpsrcop1, fptemp1;
int expdif;
- int q;
-
- fpsrcop = ST0;
- fptemp = ST1;
+ signed long long int q;
+
+ if (isinf(ST0) || isnan(ST0) || isnan(ST1) || (ST1 == 0.0)) {
+ ST0 = 0.0 / 0.0; /* NaN */
+ env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
+ return;
+ }
+
+ fpsrcop = (CPU86_LDouble)ST0;
+ fptemp = (CPU86_LDouble)ST1;
fpsrcop1.d = fpsrcop;
fptemp1.d = fptemp;
expdif = EXPD(fpsrcop1) - EXPD(fptemp1);
+
+ if (expdif < 0) {
+ /* optimisation? taken from the AMD docs */
+ env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
+ /* ST0 is unchanged */
+ return;
+ }
+
if ( expdif < 53 ) {
- dblq = fpsrcop / fptemp;
- dblq = (dblq < 0.0)? ceil(dblq): floor(dblq);
- ST0 = fpsrcop - fptemp*dblq;
- q = (int)dblq; /* cutting off top bits is assumed here */
+ dblq = fpsrcop/*ST0*/ / fptemp/*ST1*/;
+ /* round dblq towards zero */
+ dblq = (dblq < 0.0) ? ceil(dblq) : floor(dblq);
+ ST0 = fpsrcop/*ST0*/ - fptemp * dblq;
+
+ /* convert dblq to q by truncating towards zero */
+ if (dblq < 0.0)
+ q = (signed long long int)(-dblq);
+ else
+ q = (signed long long int)dblq;
+
env->fpus &= (~0x4700); /* (C3,C2,C1,C0) <-- 0000 */
- /* (C0,C1,C3) <-- (q2,q1,q0) */
- env->fpus |= (q&0x4) << 6; /* (C0) <-- q2 */
- env->fpus |= (q&0x2) << 8; /* (C1) <-- q1 */
- env->fpus |= (q&0x1) << 14; /* (C3) <-- q0 */
+ /* (C0,C3,C1) <-- (q2,q1,q0) */
+ env->fpus |= (q & 0x4) << (8 - 2); /* (C0) <-- q2 */
+ env->fpus |= (q & 0x2) << (14 - 1); /* (C3) <-- q1 */
+ env->fpus |= (q & 0x1) << (9 - 0); /* (C1) <-- q0 */
} else {
+ int N = 32 + (expdif % 32); /* as per AMD docs */
env->fpus |= 0x400; /* C2 <-- 1 */
- fptemp = pow(2.0, expdif-50);
+ fptemp = pow(2.0, (double)(expdif - N));
fpsrcop = (ST0 / ST1) / fptemp;
/* fpsrcop = integer obtained by chopping */
- fpsrcop = (fpsrcop < 0.0)?
- -(floor(fabs(fpsrcop))): floor(fpsrcop);
+ fpsrcop = (fpsrcop < 0.0) ?
+ -(floor(fabs(fpsrcop))) : floor(fpsrcop);
ST0 -= (ST1 * fpsrcop * fptemp);
}
}
@@ -3716,14 +3803,14 @@
void helper_monitor(void)
{
- if (ECX != 0)
+ if ((uint32_t)ECX != 0)
raise_exception(EXCP0D_GPF);
/* XXX: store address ? */
}
void helper_mwait(void)
{
- if (ECX != 0)
+ if ((uint32_t)ECX != 0)
raise_exception(EXCP0D_GPF);
/* XXX: not complete but not completely erroneous */
if (env->cpu_index != 0 || env->next_cpu != NULL) {
Modified: trunk/src/host/qemu-neo1973/target-i386/helper2.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-i386/helper2.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/target-i386/helper2.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -578,7 +578,7 @@
return 1;
}
-target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
+target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
{
return addr;
}
@@ -670,7 +670,7 @@
#endif
{
/* XXX: load them when cr3 is loaded ? */
- pdpe_addr = ((env->cr[3] & ~0x1f) + ((addr >> 30) << 3)) &
+ pdpe_addr = ((env->cr[3] & ~0x1f) + ((addr >> 27) & 0x18)) &
env->a20_mask;
pdpe = ldq_phys(pdpe_addr);
if (!(pdpe & PG_PRESENT_MASK)) {
@@ -765,7 +765,7 @@
uint32_t pde;
/* page directory entry */
- pde_addr = ((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3)) &
+ pde_addr = ((env->cr[3] & ~0xfff) + ((addr >> 20) & 0xffc)) &
env->a20_mask;
pde = ldl_phys(pde_addr);
if (!(pde & PG_PRESENT_MASK)) {
@@ -876,7 +876,7 @@
return 1;
}
-target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
+target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
{
uint32_t pde_addr, pte_addr;
uint32_t pde, pte, paddr, page_offset, page_size;
@@ -910,7 +910,7 @@
} else
#endif
{
- pdpe_addr = ((env->cr[3] & ~0x1f) + ((addr >> 30) << 3)) &
+ pdpe_addr = ((env->cr[3] & ~0x1f) + ((addr >> 27) & 0x18)) &
env->a20_mask;
pdpe = ldl_phys(pdpe_addr);
if (!(pdpe & PG_PRESENT_MASK))
@@ -940,7 +940,7 @@
page_size = 4096;
} else {
/* page directory entry */
- pde_addr = ((env->cr[3] & ~0xfff) + ((addr >> 20) & ~3)) & env->a20_mask;
+ pde_addr = ((env->cr[3] & ~0xfff) + ((addr >> 20) & 0xffc)) & env->a20_mask;
pde = ldl_phys(pde_addr);
if (!(pde & PG_PRESENT_MASK))
return -1;
Modified: trunk/src/host/qemu-neo1973/target-i386/op.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-i386/op.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/target-i386/op.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -788,7 +788,7 @@
void OPPROTO op_movswl_EAX_AX(void)
{
- EAX = (int16_t)EAX;
+ EAX = (uint32_t)((int16_t)EAX);
}
#ifdef TARGET_X86_64
@@ -810,7 +810,7 @@
void OPPROTO op_movslq_EDX_EAX(void)
{
- EDX = (int32_t)EAX >> 31;
+ EDX = (uint32_t)((int32_t)EAX >> 31);
}
void OPPROTO op_movswl_DX_AX(void)
Modified: trunk/src/host/qemu-neo1973/target-i386/ops_sse.h
===================================================================
--- trunk/src/host/qemu-neo1973/target-i386/ops_sse.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/target-i386/ops_sse.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -558,6 +558,25 @@
T0 = s->L(0);
}
+#ifdef TARGET_X86_64
+void OPPROTO glue(op_movq_mm_T0, SUFFIX) (void)
+{
+ Reg *d;
+ d = (Reg *)((char *)env + PARAM1);
+ d->Q(0) = T0;
+#if SHIFT == 1
+ d->Q(1) = 0;
+#endif
+}
+
+void OPPROTO glue(op_movq_T0_mm, SUFFIX) (void)
+{
+ Reg *s;
+ s = (Reg *)((char *)env + PARAM1);
+ T0 = s->Q(0);
+}
+#endif
+
#if SHIFT == 0
void OPPROTO glue(op_pshufw, SUFFIX) (void)
{
Modified: trunk/src/host/qemu-neo1973/target-i386/translate.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-i386/translate.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/target-i386/translate.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -2621,12 +2621,28 @@
gen_sto_env_A0[s->mem_index >> 2](offsetof(CPUX86State,xmm_regs[reg]));
break;
case 0x6e: /* movd mm, ea */
- gen_ldst_modrm(s, modrm, OT_LONG, OR_TMP0, 0);
- gen_op_movl_mm_T0_mmx(offsetof(CPUX86State,fpregs[reg].mmx));
+#ifdef TARGET_X86_64
+ if (s->dflag == 2) {
+ gen_ldst_modrm(s, modrm, OT_QUAD, OR_TMP0, 0);
+ gen_op_movq_mm_T0_mmx(offsetof(CPUX86State,fpregs[reg].mmx));
+ } else
+#endif
+ {
+ gen_ldst_modrm(s, modrm, OT_LONG, OR_TMP0, 0);
+ gen_op_movl_mm_T0_mmx(offsetof(CPUX86State,fpregs[reg].mmx));
+ }
break;
case 0x16e: /* movd xmm, ea */
- gen_ldst_modrm(s, modrm, OT_LONG, OR_TMP0, 0);
- gen_op_movl_mm_T0_xmm(offsetof(CPUX86State,xmm_regs[reg]));
+#ifdef TARGET_X86_64
+ if (s->dflag == 2) {
+ gen_ldst_modrm(s, modrm, OT_QUAD, OR_TMP0, 0);
+ gen_op_movq_mm_T0_xmm(offsetof(CPUX86State,xmm_regs[reg]));
+ } else
+#endif
+ {
+ gen_ldst_modrm(s, modrm, OT_LONG, OR_TMP0, 0);
+ gen_op_movl_mm_T0_xmm(offsetof(CPUX86State,xmm_regs[reg]));
+ }
break;
case 0x6f: /* movq mm, ea */
if (mod != 3) {
@@ -2750,12 +2766,28 @@
offsetof(CPUX86State,xmm_regs[reg].XMM_L(3)));
break;
case 0x7e: /* movd ea, mm */
- gen_op_movl_T0_mm_mmx(offsetof(CPUX86State,fpregs[reg].mmx));
- gen_ldst_modrm(s, modrm, OT_LONG, OR_TMP0, 1);
+#ifdef TARGET_X86_64
+ if (s->dflag == 2) {
+ gen_op_movq_T0_mm_mmx(offsetof(CPUX86State,fpregs[reg].mmx));
+ gen_ldst_modrm(s, modrm, OT_QUAD, OR_TMP0, 1);
+ } else
+#endif
+ {
+ gen_op_movl_T0_mm_mmx(offsetof(CPUX86State,fpregs[reg].mmx));
+ gen_ldst_modrm(s, modrm, OT_LONG, OR_TMP0, 1);
+ }
break;
case 0x17e: /* movd ea, xmm */
- gen_op_movl_T0_mm_xmm(offsetof(CPUX86State,xmm_regs[reg]));
- gen_ldst_modrm(s, modrm, OT_LONG, OR_TMP0, 1);
+#ifdef TARGET_X86_64
+ if (s->dflag == 2) {
+ gen_op_movq_T0_mm_xmm(offsetof(CPUX86State,xmm_regs[reg]));
+ gen_ldst_modrm(s, modrm, OT_QUAD, OR_TMP0, 1);
+ } else
+#endif
+ {
+ gen_op_movl_T0_mm_xmm(offsetof(CPUX86State,xmm_regs[reg]));
+ gen_ldst_modrm(s, modrm, OT_LONG, OR_TMP0, 1);
+ }
break;
case 0x27e: /* movq xmm, ea */
if (mod != 3) {
@@ -3765,6 +3797,7 @@
mod = (modrm >> 6) & 3;
if (mod == 3)
goto illegal_op;
+ gen_jmp_im(pc_start - s->cs_base);
if (s->cc_op != CC_OP_DYNAMIC)
gen_op_set_cc_op(s->cc_op);
gen_lea_modrm(s, modrm, ®_addr, &offset_addr);
Modified: trunk/src/host/qemu-neo1973/target-m68k/cpu.h
===================================================================
--- trunk/src/host/qemu-neo1973/target-m68k/cpu.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/target-m68k/cpu.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -97,8 +97,7 @@
/* you can call this signal handler from your SIGBUS and SIGSEGV
signal handlers to inform the virtual CPU of exceptions. non zero
is returned if the signal was handled by the virtual CPU. */
-struct siginfo;
-int cpu_m68k_signal_handler(int host_signum, struct siginfo *info,
+int cpu_m68k_signal_handler(int host_signum, void *pinfo,
void *puc);
void cpu_m68k_flush_flags(CPUM68KState *, int);
Modified: trunk/src/host/qemu-neo1973/target-m68k/translate.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-m68k/translate.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/target-m68k/translate.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -2551,8 +2551,9 @@
#endif
/* generate intermediate code for basic block 'tb'. */
-int gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
- int search_pc)
+static inline int
+gen_intermediate_code_internal(CPUState *env, TranslationBlock *tb,
+ int search_pc)
{
DisasContext dc1, *dc = &dc1;
uint16_t *gen_opc_end;
@@ -2737,7 +2738,7 @@
}
/* ??? */
-target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
+target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
{
return addr;
}
Added: trunk/src/host/qemu-neo1973/target-mips/TODO
===================================================================
--- trunk/src/host/qemu-neo1973/target-mips/TODO 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/target-mips/TODO 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,33 @@
+Unsolved issues/bugs in the mips/mipsel backend
+-----------------------------------------------
+
+General
+-------
+- [ls][dw][lr] report broken (aligned) BadVAddr
+- Missing per-CPU instruction decoding, currently all implemented
+ instructions are regarded as valid
+- Applications running on top of a emulated Linux segfault sometimes
+ when the Qemu FPU emulation is disabled. Also gdb inside the emulated
+ system does not work. Both problems are caused by insufficient
+ handling of self-modifying code.
+- Floating point exception emulation is incomplete.
+
+MIPS64
+------
+- No 64bit TLB support
+- 64bit FPU not fully implemented
+- 64bit mul/div handling broken
+
+"Generic" 4Kc system emulation
+------------------------------
+- Doesn't correspond to any real hardware.
+
+PICA 61 system emulation
+------------------------
+- No framebuffer support yet.
+
+MALTA system emulation
+----------------------
+- We fake firmware support instead of doing the real thing
+- Real firmware falls over when trying to init RAM, presumably due
+ to lacking system controller emulation.
Modified: trunk/src/host/qemu-neo1973/target-mips/cpu.h
===================================================================
--- trunk/src/host/qemu-neo1973/target-mips/cpu.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/target-mips/cpu.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -12,23 +12,16 @@
// uint_fast8_t and uint_fast16_t not in <sys/int_types.h>
// XXX: move that elsewhere
-#if defined(HOST_SOLARIS) && SOLARISREV < 10
+#if defined(HOST_SOLARIS) && HOST_SOLARIS < 10
typedef unsigned char uint_fast8_t;
typedef unsigned int uint_fast16_t;
#endif
-/* target_ulong size spec */
-#ifdef MIPS_HAS_MIPS64
-#define TLSZ "%016llx"
-#else
-#define TLSZ "%08x"
-#endif
-
typedef union fpr_t fpr_t;
union fpr_t {
float64 fd; /* ieee double precision */
float32 fs[2];/* ieee single precision */
- uint64_t d; /* binary single fixed-point */
+ uint64_t d; /* binary double fixed-point */
uint32_t w[2]; /* binary single fixed-point */
};
/* define FP_ENDIAN_IDX to access the same location
@@ -44,8 +37,7 @@
typedef struct tlb_t tlb_t;
struct tlb_t {
target_ulong VPN;
- target_ulong end;
- target_ulong end2;
+ uint32_t PageMask;
uint_fast8_t ASID;
uint_fast16_t G:1;
uint_fast16_t C0:3;
@@ -70,61 +62,63 @@
target_ulong t2;
#endif
target_ulong HI, LO;
- uint32_t DCR; /* ? */
-#if defined(MIPS_USES_FPU)
/* Floating point registers */
- fpr_t fpr[16];
-#define FPR(cpu, n) ((fpr_t*)&(cpu)->fpr[(n) / 2])
-#define FPR_FD(cpu, n) (FPR(cpu, n)->fd)
-#define FPR_FS(cpu, n) (FPR(cpu, n)->fs[((n) & 1) ^ FP_ENDIAN_IDX])
-#define FPR_D(cpu, n) (FPR(cpu, n)->d)
-#define FPR_W(cpu, n) (FPR(cpu, n)->w[((n) & 1) ^ FP_ENDIAN_IDX])
-
+ fpr_t fpr[32];
#ifndef USE_HOST_FLOAT_REGS
fpr_t ft0;
fpr_t ft1;
fpr_t ft2;
#endif
float_status fp_status;
- /* fpu implementation/revision register */
+ /* fpu implementation/revision register (fir) */
uint32_t fcr0;
+#define FCR0_F64 22
+#define FCR0_L 21
+#define FCR0_W 20
+#define FCR0_3D 19
+#define FCR0_PS 18
+#define FCR0_D 17
+#define FCR0_S 16
+#define FCR0_PRID 8
+#define FCR0_REV 0
/* fcsr */
uint32_t fcr31;
-#define SET_FP_COND(reg) do { (reg) |= (1<<23); } while(0)
-#define CLEAR_FP_COND(reg) do { (reg) &= ~(1<<23); } while(0)
-#define IS_FP_COND_SET(reg) (((reg) & (1<<23)) != 0)
-#define GET_FP_CAUSE(reg) (((reg) >> 12) & 0x3f)
-#define GET_FP_ENABLE(reg) (((reg) >> 7) & 0x1f)
-#define GET_FP_FLAGS(reg) (((reg) >> 2) & 0x1f)
-#define SET_FP_CAUSE(reg,v) do { (reg) = ((reg) & ~(0x3f << 12)) | ((v) << 12); } while(0)
-#define SET_FP_ENABLE(reg,v) do { (reg) = ((reg) & ~(0x1f << 7)) | ((v) << 7); } while(0)
-#define SET_FP_FLAGS(reg,v) do { (reg) = ((reg) & ~(0x1f << 2)) | ((v) << 2); } while(0)
+#define SET_FP_COND(num,env) do { (env->fcr31) |= ((num) ? (1 << ((num) + 24)) : (1 << ((num) + 23))); } while(0)
+#define CLEAR_FP_COND(num,env) do { (env->fcr31) &= ~((num) ? (1 << ((num) + 24)) : (1 << ((num) + 23))); } while(0)
+#define IS_FP_COND_SET(num,env) (((env->fcr31) & ((num) ? (1 << ((num) + 24)) : (1 << ((num) + 23)))) != 0)
+#define GET_FP_CAUSE(reg) (((reg) >> 12) & 0x3f)
+#define GET_FP_ENABLE(reg) (((reg) >> 7) & 0x1f)
+#define GET_FP_FLAGS(reg) (((reg) >> 2) & 0x1f)
+#define SET_FP_CAUSE(reg,v) do { (reg) = ((reg) & ~(0x3f << 12)) | ((v & 0x3f) << 12); } while(0)
+#define SET_FP_ENABLE(reg,v) do { (reg) = ((reg) & ~(0x1f << 7)) | ((v & 0x1f) << 7); } while(0)
+#define SET_FP_FLAGS(reg,v) do { (reg) = ((reg) & ~(0x1f << 2)) | ((v & 0x1f) << 2); } while(0)
+#define UPDATE_FP_FLAGS(reg,v) do { (reg) |= ((v & 0x1f) << 2); } while(0)
#define FP_INEXACT 1
#define FP_UNDERFLOW 2
#define FP_OVERFLOW 4
#define FP_DIV0 8
#define FP_INVALID 16
#define FP_UNIMPLEMENTED 32
-
-#endif
+
#if defined(MIPS_USES_R4K_TLB)
tlb_t tlb[MIPS_TLB_MAX];
uint32_t tlb_in_use;
+ uint32_t nb_tlb;
#endif
- uint32_t CP0_index;
- uint32_t CP0_random;
- uint64_t CP0_EntryLo0;
- uint64_t CP0_EntryLo1;
- uint64_t CP0_Context;
- uint32_t CP0_PageMask;
- uint32_t CP0_PageGrain;
- uint32_t CP0_Wired;
- uint32_t CP0_HWREna;
+ int32_t CP0_Index;
+ int32_t CP0_Random;
+ target_ulong CP0_EntryLo0;
+ target_ulong CP0_EntryLo1;
+ target_ulong CP0_Context;
+ int32_t CP0_PageMask;
+ int32_t CP0_PageGrain;
+ int32_t CP0_Wired;
+ int32_t CP0_HWREna;
target_ulong CP0_BadVAddr;
- uint32_t CP0_Count;
- uint64_t CP0_EntryHi;
- uint32_t CP0_Compare;
- uint32_t CP0_Status;
+ int32_t CP0_Count;
+ target_ulong CP0_EntryHi;
+ int32_t CP0_Compare;
+ int32_t CP0_Status;
#define CP0St_CU3 31
#define CP0St_CU2 30
#define CP0St_CU1 29
@@ -147,9 +141,10 @@
#define CP0St_ERL 2
#define CP0St_EXL 1
#define CP0St_IE 0
- uint32_t CP0_IntCtl;
- uint32_t CP0_SRSCtl;
- uint32_t CP0_Cause;
+ int32_t CP0_IntCtl;
+ int32_t CP0_SRSCtl;
+ int32_t CP0_SRSMap;
+ int32_t CP0_Cause;
#define CP0Ca_BD 31
#define CP0Ca_TI 30
#define CP0Ca_CE 28
@@ -158,11 +153,12 @@
#define CP0Ca_IV 23
#define CP0Ca_WP 22
#define CP0Ca_IP 8
+#define CP0Ca_IP_mask 0x0000FF00
#define CP0Ca_EC 2
target_ulong CP0_EPC;
- uint32_t CP0_PRid;
- target_ulong CP0_EBase;
- uint32_t CP0_Config0;
+ int32_t CP0_PRid;
+ int32_t CP0_EBase;
+ int32_t CP0_Config0;
#define CP0C0_M 31
#define CP0C0_K23 28
#define CP0C0_KU 25
@@ -175,7 +171,7 @@
#define CP0C0_MT 7
#define CP0C0_VI 3
#define CP0C0_K0 0
- uint32_t CP0_Config1;
+ int32_t CP0_Config1;
#define CP0C1_M 31
#define CP0C1_MMU 25
#define CP0C1_IS 22
@@ -191,7 +187,7 @@
#define CP0C1_CA 2
#define CP0C1_EP 1
#define CP0C1_FP 0
- uint32_t CP0_Config2;
+ int32_t CP0_Config2;
#define CP0C2_M 31
#define CP0C2_TU 28
#define CP0C2_TS 24
@@ -201,7 +197,7 @@
#define CP0C2_SS 8
#define CP0C2_SL 4
#define CP0C2_SA 0
- uint32_t CP0_Config3;
+ int32_t CP0_Config3;
#define CP0C3_M 31
#define CP0C3_DSPP 10
#define CP0C3_LPA 7
@@ -211,12 +207,14 @@
#define CP0C3_MT 2
#define CP0C3_SM 1
#define CP0C3_TL 0
+ int32_t CP0_Config6;
+ int32_t CP0_Config7;
target_ulong CP0_LLAddr;
- uint32_t CP0_WatchLo;
- uint32_t CP0_WatchHi;
- uint32_t CP0_XContext;
- uint32_t CP0_Framemask;
- uint32_t CP0_Debug;
+ target_ulong CP0_WatchLo;
+ int32_t CP0_WatchHi;
+ target_ulong CP0_XContext;
+ int32_t CP0_Framemask;
+ int32_t CP0_Debug;
#define CPDB_DBD 31
#define CP0DB_DM 30
#define CP0DB_LSNM 28
@@ -236,13 +234,13 @@
#define CP0DB_DBp 1
#define CP0DB_DSS 0
target_ulong CP0_DEPC;
- uint32_t CP0_Performance0;
- uint32_t CP0_TagLo;
- uint32_t CP0_DataLo;
- uint32_t CP0_TagHi;
- uint32_t CP0_DataHi;
+ int32_t CP0_Performance0;
+ int32_t CP0_TagLo;
+ int32_t CP0_DataLo;
+ int32_t CP0_TagHi;
+ int32_t CP0_DataHi;
target_ulong CP0_ErrorEPC;
- uint32_t CP0_DESAVE;
+ int32_t CP0_DESAVE;
/* Qemu */
int interrupt_request;
jmp_buf jmp_env;
@@ -254,8 +252,6 @@
#define MIPS_HFLAG_TMASK 0x007F
#define MIPS_HFLAG_MODE 0x001F /* execution modes */
#define MIPS_HFLAG_UM 0x0001 /* user mode */
-#define MIPS_HFLAG_ERL 0x0002 /* Error mode */
-#define MIPS_HFLAG_EXL 0x0004 /* Exception mode */
#define MIPS_HFLAG_DM 0x0008 /* Debug mode */
#define MIPS_HFLAG_SM 0x0010 /* Supervisor mode */
#define MIPS_HFLAG_RE 0x0040 /* Reversed endianness */
@@ -275,7 +271,14 @@
int SYNCI_Step; /* Address step size for SYNCI */
int CCRes; /* Cycle count resolution/divisor */
+ int Status_rw_bitmask; /* Read/write bits in CP0_Status */
+#if defined(CONFIG_USER_ONLY)
+ target_ulong tls_value;
+#else
+ void *irq[8];
+#endif
+
CPU_COMMON
int ram_size;
@@ -286,6 +289,11 @@
struct QEMUTimer *timer; /* Internal timer */
};
+typedef struct mips_def_t mips_def_t;
+int mips_find_by_name (const unsigned char *name, mips_def_t **def);
+void mips_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...));
+int cpu_mips_register (CPUMIPSState *env, mips_def_t *def);
+
#include "cpu-all.h"
/* Memory access type :
@@ -327,10 +335,11 @@
EXCP_RI,
EXCP_OVERFLOW,
EXCP_TRAP,
+ EXCP_FPE,
EXCP_DDBS,
EXCP_DWATCH,
- EXCP_LAE,
- EXCP_SAE, /* 24 */
+ EXCP_LAE, /* 24 */
+ EXCP_SAE,
EXCP_LTLBL,
EXCP_TLBL,
EXCP_TLBS,
Modified: trunk/src/host/qemu-neo1973/target-mips/exec.h
===================================================================
--- trunk/src/host/qemu-neo1973/target-mips/exec.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/target-mips/exec.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -6,25 +6,18 @@
#include "config.h"
#include "mips-defs.h"
#include "dyngen-exec.h"
+#include "cpu-defs.h"
register struct CPUMIPSState *env asm(AREG0);
-#if defined (USE_64BITS_REGS)
-typedef int64_t host_int_t;
-typedef uint64_t host_uint_t;
-#else
-typedef int32_t host_int_t;
-typedef uint32_t host_uint_t;
-#endif
-
#if TARGET_LONG_BITS > HOST_LONG_BITS
#define T0 (env->t0)
#define T1 (env->t1)
#define T2 (env->t2)
#else
-register host_uint_t T0 asm(AREG1);
-register host_uint_t T1 asm(AREG2);
-register host_uint_t T2 asm(AREG3);
+register target_ulong T0 asm(AREG1);
+register target_ulong T1 asm(AREG2);
+register target_ulong T2 asm(AREG3);
#endif
#if defined (USE_HOST_FLOAT_REGS)
@@ -36,12 +29,18 @@
#define FST0 (env->ft0.fs[FP_ENDIAN_IDX])
#define FST1 (env->ft1.fs[FP_ENDIAN_IDX])
#define FST2 (env->ft2.fs[FP_ENDIAN_IDX])
+#define FSTH0 (env->ft0.fs[!FP_ENDIAN_IDX])
+#define FSTH1 (env->ft1.fs[!FP_ENDIAN_IDX])
+#define FSTH2 (env->ft2.fs[!FP_ENDIAN_IDX])
#define DT0 (env->ft0.d)
#define DT1 (env->ft1.d)
#define DT2 (env->ft2.d)
#define WT0 (env->ft0.w[FP_ENDIAN_IDX])
#define WT1 (env->ft1.w[FP_ENDIAN_IDX])
#define WT2 (env->ft2.w[FP_ENDIAN_IDX])
+#define WTH0 (env->ft0.w[!FP_ENDIAN_IDX])
+#define WTH1 (env->ft1.w[!FP_ENDIAN_IDX])
+#define WTH2 (env->ft2.w[!FP_ENDIAN_IDX])
#endif
#if defined (DEBUG_OP)
@@ -65,7 +64,7 @@
{
}
-#ifdef MIPS_HAS_MIPS64
+#ifdef TARGET_MIPS64
#if TARGET_LONG_BITS > HOST_LONG_BITS
void do_dsll (void);
void do_dsll32 (void);
@@ -82,6 +81,9 @@
#endif
#endif
+#if HOST_LONG_BITS < 64
+void do_div (void);
+#endif
#if TARGET_LONG_BITS > HOST_LONG_BITS
void do_mult (void);
void do_multu (void);
@@ -89,10 +91,12 @@
void do_maddu (void);
void do_msub (void);
void do_msubu (void);
+#endif
+#ifdef TARGET_MIPS64
void do_ddiv (void);
+#if TARGET_LONG_BITS > HOST_LONG_BITS
void do_ddivu (void);
#endif
-#ifdef MIPS_HAS_MIPS64
void do_dmult (void);
void do_dmultu (void);
#endif
@@ -105,18 +109,16 @@
void do_tlbwr (void);
void do_tlbp (void);
void do_tlbr (void);
-#ifdef MIPS_USES_FPU
void dump_fpu(CPUState *env);
void fpu_dump_state(CPUState *env, FILE *f,
int (*fpu_fprintf)(FILE *f, const char *fmt, ...),
int flags);
-#endif
void dump_sc (void);
void do_lwl_raw (uint32_t);
void do_lwr_raw (uint32_t);
uint32_t do_swl_raw (uint32_t);
uint32_t do_swr_raw (uint32_t);
-#ifdef MIPS_HAS_MIPS64
+#ifdef TARGET_MIPS64
void do_ldl_raw (uint64_t);
void do_ldr_raw (uint64_t);
uint64_t do_sdl_raw (uint64_t);
@@ -131,7 +133,7 @@
uint32_t do_swl_kernel (uint32_t);
uint32_t do_swr_user (uint32_t);
uint32_t do_swr_kernel (uint32_t);
-#ifdef MIPS_HAS_MIPS64
+#ifdef TARGET_MIPS64
void do_ldl_user (uint64_t);
void do_ldl_kernel (uint64_t);
void do_ldr_user (uint64_t);
@@ -154,6 +156,7 @@
void cpu_loop_exit(void);
void do_raise_exception_err (uint32_t exception, int error_code);
void do_raise_exception (uint32_t exception);
+void do_raise_exception_direct_err (uint32_t exception, int error_code);
void do_raise_exception_direct (uint32_t exception);
void cpu_dump_state(CPUState *env, FILE *f,
@@ -164,6 +167,7 @@
uint32_t cpu_mips_get_count (CPUState *env);
void cpu_mips_store_count (CPUState *env, uint32_t value);
void cpu_mips_store_compare (CPUState *env, uint32_t value);
+void cpu_mips_update_irq (CPUState *env);
void cpu_mips_clock_init (CPUState *env);
void cpu_mips_tlb_flush (CPUState *env, int flush_global);
Modified: trunk/src/host/qemu-neo1973/target-mips/fop_template.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-mips/fop_template.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/target-mips/fop_template.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -19,75 +19,103 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#if defined(SFREG)
+#if defined(FREG)
-#define OP_WLOAD_FREG(treg, tregname, SFREG) \
- void glue(glue(op_load_fpr_,tregname), SFREG) (void) \
- { \
- treg = FPR_W(env, SFREG); \
- RETURN(); \
+#define OP_WLOAD_FREG(treg, tregname, FREG) \
+ void glue(glue(op_load_fpr_,tregname), FREG) (void) \
+ { \
+ treg = env->fpr[FREG].fs[FP_ENDIAN_IDX]; \
+ RETURN(); \
}
-#define OP_WSTORE_FREG(treg, tregname, SFREG) \
- void glue(glue(op_store_fpr_,tregname), SFREG) (void)\
- { \
- FPR_W(env, SFREG) = treg; \
- RETURN(); \
+#define OP_WSTORE_FREG(treg, tregname, FREG) \
+ void glue(glue(op_store_fpr_,tregname), FREG) (void) \
+ { \
+ env->fpr[FREG].fs[FP_ENDIAN_IDX] = treg; \
+ RETURN(); \
}
-/* WT0 = SFREG.w: op_load_fpr_WT0_fprSFREG */
-OP_WLOAD_FREG(WT0, WT0_fpr, SFREG)
-/* SFREG.w = WT0: op_store_fpr_WT0_fprSFREG */
-OP_WSTORE_FREG(WT0, WT0_fpr, SFREG)
+/* WT0 = FREG.w: op_load_fpr_WT0_fprFREG */
+OP_WLOAD_FREG(WT0, WT0_fpr, FREG)
+/* FREG.w = WT0: op_store_fpr_WT0_fprFREG */
+OP_WSTORE_FREG(WT0, WT0_fpr, FREG)
-OP_WLOAD_FREG(WT1, WT1_fpr, SFREG)
-OP_WSTORE_FREG(WT1, WT1_fpr, SFREG)
+OP_WLOAD_FREG(WT1, WT1_fpr, FREG)
+OP_WSTORE_FREG(WT1, WT1_fpr, FREG)
-OP_WLOAD_FREG(WT2, WT2_fpr, SFREG)
-OP_WSTORE_FREG(WT2, WT2_fpr, SFREG)
+OP_WLOAD_FREG(WT2, WT2_fpr, FREG)
+OP_WSTORE_FREG(WT2, WT2_fpr, FREG)
-#endif
+#define OP_DLOAD_FREG(treg, tregname, FREG) \
+ void glue(glue(op_load_fpr_,tregname), FREG) (void) \
+ { \
+ if (env->CP0_Status & (1 << CP0St_FR)) \
+ treg = env->fpr[FREG].fd; \
+ else \
+ treg = (uint64_t)(env->fpr[FREG | 1].fs[FP_ENDIAN_IDX]) << 32 | \
+ env->fpr[FREG & ~1].fs[FP_ENDIAN_IDX]; \
+ RETURN(); \
+ }
-#if defined(DFREG)
+#define OP_DSTORE_FREG(treg, tregname, FREG) \
+ void glue(glue(op_store_fpr_,tregname), FREG) (void) \
+ { \
+ if (env->CP0_Status & (1 << CP0St_FR)) \
+ env->fpr[FREG].fd = treg; \
+ else { \
+ env->fpr[FREG | 1].fs[FP_ENDIAN_IDX] = treg >> 32; \
+ env->fpr[FREG & ~1].fs[FP_ENDIAN_IDX] = treg; \
+ } \
+ RETURN(); \
+ }
-#define OP_DLOAD_FREG(treg, tregname, DFREG) \
- void glue(glue(op_load_fpr_,tregname), DFREG) (void) \
- { \
- treg = FPR_D(env, DFREG); \
- RETURN(); \
+OP_DLOAD_FREG(DT0, DT0_fpr, FREG)
+OP_DSTORE_FREG(DT0, DT0_fpr, FREG)
+
+OP_DLOAD_FREG(DT1, DT1_fpr, FREG)
+OP_DSTORE_FREG(DT1, DT1_fpr, FREG)
+
+OP_DLOAD_FREG(DT2, DT2_fpr, FREG)
+OP_DSTORE_FREG(DT2, DT2_fpr, FREG)
+
+#define OP_PSLOAD_FREG(treg, tregname, FREG) \
+ void glue(glue(op_load_fpr_,tregname), FREG) (void) \
+ { \
+ treg = env->fpr[FREG].fs[!FP_ENDIAN_IDX]; \
+ RETURN(); \
}
-#define OP_DSTORE_FREG(treg, tregname, DFREG) \
- void glue(glue(op_store_fpr_,tregname), DFREG) (void)\
- { \
- FPR_D(env, DFREG) = treg; \
- RETURN(); \
+#define OP_PSSTORE_FREG(treg, tregname, FREG) \
+ void glue(glue(op_store_fpr_,tregname), FREG) (void) \
+ { \
+ env->fpr[FREG].fs[!FP_ENDIAN_IDX] = treg; \
+ RETURN(); \
}
-OP_DLOAD_FREG(DT0, DT0_fpr, DFREG)
-OP_DSTORE_FREG(DT0, DT0_fpr, DFREG)
+OP_PSLOAD_FREG(WTH0, WTH0_fpr, FREG)
+OP_PSSTORE_FREG(WTH0, WTH0_fpr, FREG)
-OP_DLOAD_FREG(DT1, DT1_fpr, DFREG)
-OP_DSTORE_FREG(DT1, DT1_fpr, DFREG)
+OP_PSLOAD_FREG(WTH1, WTH1_fpr, FREG)
+OP_PSSTORE_FREG(WTH1, WTH1_fpr, FREG)
-OP_DLOAD_FREG(DT2, DT2_fpr, DFREG)
-OP_DSTORE_FREG(DT2, DT2_fpr, DFREG)
+OP_PSLOAD_FREG(WTH2, WTH2_fpr, FREG)
+OP_PSSTORE_FREG(WTH2, WTH2_fpr, FREG)
#endif
#if defined (FTN)
-#define SET_RESET(treg, tregname) \
+#define SET_RESET(treg, tregname) \
void glue(op_set, tregname)(void) \
- { \
- treg = PARAM1; \
- RETURN(); \
- } \
+ { \
+ treg = PARAM1; \
+ RETURN(); \
+ } \
void glue(op_reset, tregname)(void) \
- { \
- treg = 0; \
- RETURN(); \
- } \
+ { \
+ treg = 0; \
+ RETURN(); \
+ }
SET_RESET(WT0, _WT0)
SET_RESET(WT1, _WT1)
@@ -95,6 +123,9 @@
SET_RESET(DT0, _DT0)
SET_RESET(DT1, _DT1)
SET_RESET(DT2, _DT2)
+SET_RESET(WTH0, _WTH0)
+SET_RESET(WTH1, _WTH1)
+SET_RESET(WTH2, _WTH2)
#undef SET_RESET
#endif
Modified: trunk/src/host/qemu-neo1973/target-mips/helper.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-mips/helper.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/target-mips/helper.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -41,23 +41,26 @@
static int map_address (CPUState *env, target_ulong *physical, int *prot,
target_ulong address, int rw, int access_type)
{
- target_ulong tag = address & (TARGET_PAGE_MASK << 1);
uint8_t ASID = env->CP0_EntryHi & 0xFF;
- tlb_t *tlb;
- int i, n;
+ int i;
for (i = 0; i < env->tlb_in_use; i++) {
- tlb = &env->tlb[i];
+ tlb_t *tlb = &env->tlb[i];
+ /* 1k pages are not supported. */
+ target_ulong mask = tlb->PageMask | 0x1FFF;
+ target_ulong tag = address & ~mask;
+ int n;
+
/* Check ASID, virtual page number & size */
if ((tlb->G == 1 || tlb->ASID == ASID) &&
- tlb->VPN == tag && address < tlb->end2) {
+ tlb->VPN == tag) {
/* TLB match */
- n = (address >> TARGET_PAGE_BITS) & 1;
+ n = !!(address & mask & ~(mask >> 1));
/* Check access rights */
if (!(n ? tlb->V1 : tlb->V0))
return TLBRET_INVALID;
if (rw == 0 || (n ? tlb->D1 : tlb->D0)) {
- *physical = tlb->PFN[n] | (address & ~TARGET_PAGE_MASK);
+ *physical = tlb->PFN[n] | (address & (mask >> 1));
*prot = PAGE_READ;
if (n ? tlb->D1 : tlb->D0)
*prot |= PAGE_WRITE;
@@ -74,8 +77,13 @@
int *prot, target_ulong address,
int rw, int access_type)
{
- /* User mode can only access useg */
+ /* User mode can only access useg/xuseg */
int user_mode = (env->hflags & MIPS_HFLAG_MODE) == MIPS_HFLAG_UM;
+#ifdef TARGET_MIPS64
+ int UX = (env->CP0_Status & (1 << CP0St_UX)) != 0;
+ int SX = (env->CP0_Status & (1 << CP0St_SX)) != 0;
+ int KX = (env->CP0_Status & (1 << CP0St_KX)) != 0;
+#endif
int ret = TLBRET_MATCH;
#if 0
@@ -84,10 +92,18 @@
user_mode, env->hflags);
}
#endif
+
+#ifdef TARGET_MIPS64
+ if (user_mode && address > 0x3FFFFFFFFFFFFFFFULL)
+ return TLBRET_BADADDR;
+#else
if (user_mode && address > 0x7FFFFFFFUL)
return TLBRET_BADADDR;
- if (address < (int32_t)0x80000000UL) {
- if (!(env->hflags & MIPS_HFLAG_ERL)) {
+#endif
+
+ if (address <= (int32_t)0x7FFFFFFFUL) {
+ /* useg */
+ if (!(env->CP0_Status & (1 << CP0St_ERL) && user_mode)) {
#ifdef MIPS_USES_R4K_TLB
ret = map_address(env, physical, prot, address, rw, access_type);
#else
@@ -98,6 +114,45 @@
*physical = address;
*prot = PAGE_READ | PAGE_WRITE;
}
+#ifdef TARGET_MIPS64
+/*
+ XXX: Assuming :
+ - PABITS = 36 (correct for MIPS64R1)
+ - SEGBITS = 40
+*/
+ } else if (address < 0x3FFFFFFFFFFFFFFFULL) {
+ /* xuseg */
+ if (UX && address < 0x000000FFFFFFFFFFULL) {
+ ret = map_address(env, physical, prot, address, rw, access_type);
+ } else {
+ ret = TLBRET_BADADDR;
+ }
+ } else if (address < 0x7FFFFFFFFFFFFFFFULL) {
+ /* xsseg */
+ if (SX && address < 0x400000FFFFFFFFFFULL) {
+ ret = map_address(env, physical, prot, address, rw, access_type);
+ } else {
+ ret = TLBRET_BADADDR;
+ }
+ } else if (address < 0xBFFFFFFFFFFFFFFFULL) {
+ /* xkphys */
+ /* XXX: check supervisor mode */
+ if (KX && (address & 0x03FFFFFFFFFFFFFFULL) < 0X0000000FFFFFFFFFULL)
+ {
+ *physical = address & 0X000000FFFFFFFFFFULL;
+ *prot = PAGE_READ | PAGE_WRITE;
+ } else {
+ ret = TLBRET_BADADDR;
+ }
+ } else if (address < 0xFFFFFFFF7FFFFFFFULL) {
+ /* xkseg */
+ /* XXX: check supervisor mode */
+ if (KX && address < 0xC00000FF7FFFFFFFULL) {
+ ret = map_address(env, physical, prot, address, rw, access_type);
+ } else {
+ ret = TLBRET_BADADDR;
+ }
+#endif
} else if (address < (int32_t)0xA0000000UL) {
/* kseg0 */
/* XXX: check supervisor mode */
@@ -113,7 +168,7 @@
#ifdef MIPS_USES_R4K_TLB
ret = map_address(env, physical, prot, address, rw, access_type);
#else
- *physical = address;
+ *physical = address & 0xFFFFFFFF;
*prot = PAGE_READ | PAGE_WRITE;
#endif
} else {
@@ -123,13 +178,13 @@
#ifdef MIPS_USES_R4K_TLB
ret = map_address(env, physical, prot, address, rw, access_type);
#else
- *physical = address;
+ *physical = address & 0xFFFFFFFF;
*prot = PAGE_READ | PAGE_WRITE;
#endif
}
#if 0
if (logfile) {
- fprintf(logfile, TLSZ " %d %d => " TLSZ " %d (%d)\n",
+ fprintf(logfile, TARGET_FMT_lx " %d %d => " TARGET_FMT_lx " %d (%d)\n",
address, rw, access_type, *physical, *prot, ret);
}
#endif
@@ -138,12 +193,12 @@
}
#if defined(CONFIG_USER_ONLY)
-target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
+target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
{
return addr;
}
#else
-target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
+target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
{
target_ulong phys_addr;
int prot;
@@ -171,7 +226,7 @@
#if 0
cpu_dump_state(env, logfile, fprintf, 0);
#endif
- fprintf(logfile, "%s pc " TLSZ " ad " TLSZ " rw %d is_user %d smmu %d\n",
+ fprintf(logfile, "%s pc " TARGET_FMT_lx " ad " TARGET_FMT_lx " rw %d is_user %d smmu %d\n",
__func__, env->PC, address, rw, is_user, is_softmmu);
}
@@ -189,7 +244,7 @@
ret = get_physical_address(env, &physical, &prot,
address, rw, access_type);
if (logfile) {
- fprintf(logfile, "%s address=" TLSZ " ret %d physical " TLSZ " prot %d\n",
+ fprintf(logfile, "%s address=" TARGET_FMT_lx " ret %d physical " TARGET_FMT_lx " prot %d\n",
__func__, address, ret, physical, prot);
}
if (ret == TLBRET_MATCH) {
@@ -255,7 +310,7 @@
int cause = -1;
if (logfile && env->exception_index != EXCP_EXT_INTERRUPT) {
- fprintf(logfile, "%s enter: PC " TLSZ " EPC " TLSZ " cause %d excp %d\n",
+ fprintf(logfile, "%s enter: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx " cause %d excp %d\n",
__func__, env->PC, env->CP0_EPC, cause, env->exception_index);
}
if (env->exception_index == EXCP_EXT_INTERRUPT &&
@@ -286,7 +341,6 @@
goto set_DEPC;
case EXCP_DDBL:
env->CP0_Debug |= 1 << CP0DB_DDBL;
- goto set_DEPC;
set_DEPC:
if (env->hflags & MIPS_HFLAG_BMASK) {
/* If the exception was raised from a delay slot,
@@ -298,18 +352,21 @@
}
enter_debug_mode:
env->hflags |= MIPS_HFLAG_DM;
+ env->hflags &= ~MIPS_HFLAG_UM;
/* EJTAG probe trap enable is not implemented... */
+ if (!(env->CP0_Status & (1 << CP0St_EXL)))
+ env->CP0_Cause &= ~(1 << CP0Ca_BD);
env->PC = (int32_t)0xBFC00480;
break;
case EXCP_RESET:
cpu_reset(env);
break;
case EXCP_SRESET:
- env->CP0_Status = (1 << CP0St_SR);
+ env->CP0_Status |= (1 << CP0St_SR);
env->CP0_WatchLo = 0;
goto set_error_EPC;
case EXCP_NMI:
- env->CP0_Status = (1 << CP0St_NMI);
+ env->CP0_Status |= (1 << CP0St_NMI);
set_error_EPC:
if (env->hflags & MIPS_HFLAG_BMASK) {
/* If the exception was raised from a delay slot,
@@ -319,8 +376,10 @@
} else {
env->CP0_ErrorEPC = env->PC;
}
- env->hflags |= MIPS_HFLAG_ERL;
- env->CP0_Status |= (1 << CP0St_ERL) | (1 << CP0St_BEV);
+ env->CP0_Status |= (1 << CP0St_ERL) | (1 << CP0St_BEV);
+ env->hflags &= ~MIPS_HFLAG_UM;
+ if (!(env->CP0_Status & (1 << CP0St_EXL)))
+ env->CP0_Cause &= ~(1 << CP0Ca_BD);
env->PC = (int32_t)0xBFC00000;
break;
case EXCP_MCHECK:
@@ -336,12 +395,14 @@
/* XXX: TODO: manage defered watch exceptions */
goto set_EPC;
case EXCP_AdEL:
- case EXCP_AdES:
cause = 4;
goto set_EPC;
+ case EXCP_AdES:
+ cause = 5;
+ goto set_EPC;
case EXCP_TLBL:
cause = 2;
- if (env->error_code == 1 && !(env->hflags & MIPS_HFLAG_EXL))
+ if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL)))
offset = 0x000;
goto set_EPC;
case EXCP_IBE:
@@ -361,7 +422,8 @@
goto set_EPC;
case EXCP_CpU:
cause = 11;
- env->CP0_Cause = (env->CP0_Cause & ~0x03000000) | (env->error_code << 28);
+ env->CP0_Cause = (env->CP0_Cause & ~(0x3 << CP0Ca_CE)) |
+ (env->error_code << CP0Ca_CE);
goto set_EPC;
case EXCP_OVERFLOW:
cause = 12;
@@ -369,34 +431,38 @@
case EXCP_TRAP:
cause = 13;
goto set_EPC;
+ case EXCP_FPE:
+ cause = 15;
+ goto set_EPC;
case EXCP_LTLBL:
cause = 1;
goto set_EPC;
case EXCP_TLBS:
cause = 3;
- if (env->error_code == 1 && !(env->hflags & MIPS_HFLAG_EXL))
+ if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL)))
offset = 0x000;
- goto set_EPC;
set_EPC:
- if (env->hflags & MIPS_HFLAG_BMASK) {
- /* If the exception was raised from a delay slot,
- come back to the jump. */
- env->CP0_EPC = env->PC - 4;
- env->CP0_Cause |= 0x80000000;
- env->hflags &= ~MIPS_HFLAG_BMASK;
- } else {
- env->CP0_EPC = env->PC;
- env->CP0_Cause &= ~0x80000000;
+ if (!(env->CP0_Status & (1 << CP0St_EXL))) {
+ if (env->hflags & MIPS_HFLAG_BMASK) {
+ /* If the exception was raised from a delay slot,
+ come back to the jump. */
+ env->CP0_EPC = env->PC - 4;
+ env->CP0_Cause |= (1 << CP0Ca_BD);
+ } else {
+ env->CP0_EPC = env->PC;
+ env->CP0_Cause &= ~(1 << CP0Ca_BD);
+ }
+ env->CP0_Status |= (1 << CP0St_EXL);
+ env->hflags &= ~MIPS_HFLAG_UM;
}
+ env->hflags &= ~MIPS_HFLAG_BMASK;
if (env->CP0_Status & (1 << CP0St_BEV)) {
env->PC = (int32_t)0xBFC00200;
} else {
- env->PC = (int32_t)0x80000000;
+ env->PC = (int32_t)(env->CP0_EBase & ~0x3ff);
}
- env->hflags |= MIPS_HFLAG_EXL;
- env->CP0_Status |= (1 << CP0St_EXL);
env->PC += offset;
- env->CP0_Cause = (env->CP0_Cause & ~0x7C) | (cause << 2);
+ env->CP0_Cause = (env->CP0_Cause & ~(0x1f << CP0Ca_EC)) | (cause << CP0Ca_EC);
break;
default:
if (logfile) {
@@ -407,8 +473,8 @@
exit(1);
}
if (logfile && env->exception_index != EXCP_EXT_INTERRUPT) {
- fprintf(logfile, "%s: PC " TLSZ " EPC " TLSZ " cause %d excp %d\n"
- " S %08x C %08x A " TLSZ " D " TLSZ "\n",
+ fprintf(logfile, "%s: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx " cause %d excp %d\n"
+ " S %08x C %08x A " TARGET_FMT_lx " D " TARGET_FMT_lx "\n",
__func__, env->PC, env->CP0_EPC, cause, env->exception_index,
env->CP0_Status, env->CP0_Cause, env->CP0_BadVAddr,
env->CP0_DEPC);
@@ -421,10 +487,10 @@
{
tlb_t *tlb;
target_ulong addr;
- uint8_t ASID;
+ target_ulong end;
+ uint8_t ASID = env->CP0_EntryHi & 0xFF;
+ target_ulong mask;
- ASID = env->CP0_EntryHi & 0xFF;
-
tlb = &env->tlb[idx];
/* The qemu TLB is flushed then the ASID changes, so no need to
flush these entries again. */
@@ -441,19 +507,23 @@
return;
}
+ /* 1k pages are not supported. */
+ mask = tlb->PageMask | 0x1FFF;
if (tlb->V0) {
addr = tlb->VPN;
- while (addr < tlb->end) {
+ end = addr | (mask >> 1);
+ while (addr < end) {
tlb_flush_page (env, addr);
addr += TARGET_PAGE_SIZE;
}
}
if (tlb->V1) {
- addr = tlb->end;
- while (addr < tlb->end2) {
+ addr = tlb->VPN | ((mask >> 1) + 1);
+ addr = tlb->VPN + TARGET_PAGE_SIZE;
+ end = addr | mask;
+ while (addr < end) {
tlb_flush_page (env, addr);
addr += TARGET_PAGE_SIZE;
}
}
}
-
Modified: trunk/src/host/qemu-neo1973/target-mips/mips-defs.h
===================================================================
--- trunk/src/host/qemu-neo1973/target-mips/mips-defs.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/target-mips/mips-defs.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -1,93 +1,24 @@
#if !defined (__QEMU_MIPS_DEFS_H__)
#define __QEMU_MIPS_DEFS_H__
-/* If we want to use 64 bits host regs... */
-//#define USE_64BITS_REGS
/* If we want to use host float regs... */
//#define USE_HOST_FLOAT_REGS
-#define MIPS_R4Kc 0x00018000
-#define MIPS_R4Kp 0x00018300
-
-/* Emulate MIPS R4Kc for now */
-#define MIPS_CPU MIPS_R4Kc
-
-#if (MIPS_CPU == MIPS_R4Kc)
-/* 32 bits target */
-#undef MIPS_HAS_MIPS64
-//#define MIPS_HAS_MIPS64 1
/* real pages are variable size... */
#define TARGET_PAGE_BITS 12
-/* Uses MIPS R4Kx enhancements to MIPS32 architecture */
-#define MIPS_USES_R4K_EXT
/* Uses MIPS R4Kc TLB model */
#define MIPS_USES_R4K_TLB
-#define MIPS_TLB_NB 16
#define MIPS_TLB_MAX 128
-/* basic FPU register support */
-#define MIPS_USES_FPU 1
-/* Define a implementation number of 1.
- * Define a major version 1, minor version 0.
- */
-#define MIPS_FCR0 ((0 << 16) | (1 << 8) | (1 << 4) | 0)
- /* Have config1, is MIPS32R1, uses TLB, no virtual icache,
- uncached coherency */
-#define MIPS_CONFIG0_1 \
- ((1 << CP0C0_M) | (0x0 << CP0C0_K23) | (0x0 << CP0C0_KU) | \
- (0x0 << CP0C0_AT) | (0x0 << CP0C0_AR) | (0x1 << CP0C0_MT) | \
- (0x2 << CP0C0_K0))
-#ifdef TARGET_WORDS_BIGENDIAN
-#define MIPS_CONFIG0 (MIPS_CONFIG0_1 | (1 << CP0C0_BE))
-#else
-#define MIPS_CONFIG0 MIPS_CONFIG0_1
-#endif
-/* Have config2, 16 TLB entries, 64 sets Icache, 16 bytes Icache line,
- 2-way Icache, 64 sets Dcache, 16 bytes Dcache line, 2-way Dcache,
- no coprocessor2 attached, no MDMX support attached,
- no performance counters, watch registers present,
- no code compression, EJTAG present, FPU enable bit depending on
- MIPS_USES_FPU */
-#define MIPS_CONFIG1_1 \
-((1 << CP0C1_M) | ((MIPS_TLB_NB - 1) << CP0C1_MMU) | \
- (0x0 << CP0C1_IS) | (0x3 << CP0C1_IL) | (0x1 << CP0C1_IA) | \
- (0x0 << CP0C1_DS) | (0x3 << CP0C1_DL) | (0x1 << CP0C1_DA) | \
- (0 << CP0C1_C2) | (0 << CP0C1_MD) | (0 << CP0C1_PC) | \
- (1 << CP0C1_WR) | (0 << CP0C1_CA) | (1 << CP0C1_EP))
-#ifdef MIPS_USES_FPU
-#define MIPS_CONFIG1 (MIPS_CONFIG1_1 | (1 << CP0C1_FP))
-#else
-#define MIPS_CONFIG1 (MIPS_CONFIG1_1 | (0 << CP0C1_FP))
-#endif
-/* Have config3, no tertiary/secondary caches implemented */
-#define MIPS_CONFIG2 \
-((1 << CP0C2_M))
-/* No config4, no DSP ASE, no large physaddr,
- no external interrupt controller, no vectored interupts,
- no 1kb pages, no MT ASE, no SmartMIPS ASE, no trace logic */
-#define MIPS_CONFIG3 \
-((0 << CP0C3_M) | (0 << CP0C3_DSPP) | (0 << CP0C3_LPA) | \
- (0 << CP0C3_VEIC) | (0 << CP0C3_VInt) | (0 << CP0C3_SP) | \
- (0 << CP0C3_MT) | (0 << CP0C3_SM) | (0 << CP0C3_TL))
-#elif (MIPS_CPU == MIPS_R4Kp)
-/* 32 bits target */
-#undef MIPS_HAS_MIPS64
-/* real pages are variable size... */
-#define TARGET_PAGE_BITS 12
-/* Uses MIPS R4Kx enhancements to MIPS32 architecture */
-#define MIPS_USES_R4K_EXT
-/* Uses MIPS R4Km FPM MMU model */
-#define MIPS_USES_R4K_FPM
-#else
-#error "MIPS CPU not defined"
-/* Reminder for other flags */
-//#undef MIPS_HAS_MIPS64
-//#define MIPS_USES_FPU
-#endif
-#ifdef MIPS_HAS_MIPS64
+#ifdef TARGET_MIPS64
#define TARGET_LONG_BITS 64
#else
#define TARGET_LONG_BITS 32
#endif
+/* Strictly follow the architecture standard:
+ - Disallow "special" instruction handling for PMON/SPIM.
+ Note that we still maintain Count/Compare to match the host clock. */
+//#define MIPS_STRICT_STANDARD 1
+
#endif /* !defined (__QEMU_MIPS_DEFS_H__) */
Modified: trunk/src/host/qemu-neo1973/target-mips/op.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-mips/op.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/target-mips/op.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -23,27 +23,27 @@
#include "exec.h"
#ifndef CALL_FROM_TB0
-#define CALL_FROM_TB0(func) func();
+#define CALL_FROM_TB0(func) func()
#endif
#ifndef CALL_FROM_TB1
-#define CALL_FROM_TB1(func, arg0) func(arg0);
+#define CALL_FROM_TB1(func, arg0) func(arg0)
#endif
#ifndef CALL_FROM_TB1_CONST16
-#define CALL_FROM_TB1_CONST16(func, arg0) CALL_FROM_TB1(func, arg0);
+#define CALL_FROM_TB1_CONST16(func, arg0) CALL_FROM_TB1(func, arg0)
#endif
#ifndef CALL_FROM_TB2
-#define CALL_FROM_TB2(func, arg0, arg1) func(arg0, arg1);
+#define CALL_FROM_TB2(func, arg0, arg1) func(arg0, arg1)
#endif
#ifndef CALL_FROM_TB2_CONST16
#define CALL_FROM_TB2_CONST16(func, arg0, arg1) \
-CALL_FROM_TB2(func, arg0, arg1);
+ CALL_FROM_TB2(func, arg0, arg1)
#endif
#ifndef CALL_FROM_TB3
-#define CALL_FROM_TB3(func, arg0, arg1, arg2) func(arg0, arg1, arg2);
+#define CALL_FROM_TB3(func, arg0, arg1, arg2) func(arg0, arg1, arg2)
#endif
#ifndef CALL_FROM_TB4
#define CALL_FROM_TB4(func, arg0, arg1, arg2, arg3) \
- func(arg0, arg1, arg2, arg3);
+ func(arg0, arg1, arg2, arg3)
#endif
#define REG 1
@@ -144,143 +144,107 @@
#include "op_template.c"
#undef TN
-#ifdef MIPS_USES_FPU
-
-#define SFREG 0
-#define DFREG 0
+#define FREG 0
#include "fop_template.c"
-#undef SFREG
-#undef DFREG
-#define SFREG 1
+#undef FREG
+#define FREG 1
#include "fop_template.c"
-#undef SFREG
-#define SFREG 2
-#define DFREG 2
+#undef FREG
+#define FREG 2
#include "fop_template.c"
-#undef SFREG
-#undef DFREG
-#define SFREG 3
+#undef FREG
+#define FREG 3
#include "fop_template.c"
-#undef SFREG
-#define SFREG 4
-#define DFREG 4
+#undef FREG
+#define FREG 4
#include "fop_template.c"
-#undef SFREG
-#undef DFREG
-#define SFREG 5
+#undef FREG
+#define FREG 5
#include "fop_template.c"
-#undef SFREG
-#define SFREG 6
-#define DFREG 6
+#undef FREG
+#define FREG 6
#include "fop_template.c"
-#undef SFREG
-#undef DFREG
-#define SFREG 7
+#undef FREG
+#define FREG 7
#include "fop_template.c"
-#undef SFREG
-#define SFREG 8
-#define DFREG 8
+#undef FREG
+#define FREG 8
#include "fop_template.c"
-#undef SFREG
-#undef DFREG
-#define SFREG 9
+#undef FREG
+#define FREG 9
#include "fop_template.c"
-#undef SFREG
-#define SFREG 10
-#define DFREG 10
+#undef FREG
+#define FREG 10
#include "fop_template.c"
-#undef SFREG
-#undef DFREG
-#define SFREG 11
+#undef FREG
+#define FREG 11
#include "fop_template.c"
-#undef SFREG
-#define SFREG 12
-#define DFREG 12
+#undef FREG
+#define FREG 12
#include "fop_template.c"
-#undef SFREG
-#undef DFREG
-#define SFREG 13
+#undef FREG
+#define FREG 13
#include "fop_template.c"
-#undef SFREG
-#define SFREG 14
-#define DFREG 14
+#undef FREG
+#define FREG 14
#include "fop_template.c"
-#undef SFREG
-#undef DFREG
-#define SFREG 15
+#undef FREG
+#define FREG 15
#include "fop_template.c"
-#undef SFREG
-#define SFREG 16
-#define DFREG 16
+#undef FREG
+#define FREG 16
#include "fop_template.c"
-#undef SFREG
-#undef DFREG
-#define SFREG 17
+#undef FREG
+#define FREG 17
#include "fop_template.c"
-#undef SFREG
-#define SFREG 18
-#define DFREG 18
+#undef FREG
+#define FREG 18
#include "fop_template.c"
-#undef SFREG
-#undef DFREG
-#define SFREG 19
+#undef FREG
+#define FREG 19
#include "fop_template.c"
-#undef SFREG
-#define SFREG 20
-#define DFREG 20
+#undef FREG
+#define FREG 20
#include "fop_template.c"
-#undef SFREG
-#undef DFREG
-#define SFREG 21
+#undef FREG
+#define FREG 21
#include "fop_template.c"
-#undef SFREG
-#define SFREG 22
-#define DFREG 22
+#undef FREG
+#define FREG 22
#include "fop_template.c"
-#undef SFREG
-#undef DFREG
-#define SFREG 23
+#undef FREG
+#define FREG 23
#include "fop_template.c"
-#undef SFREG
-#define SFREG 24
-#define DFREG 24
+#undef FREG
+#define FREG 24
#include "fop_template.c"
-#undef SFREG
-#undef DFREG
-#define SFREG 25
+#undef FREG
+#define FREG 25
#include "fop_template.c"
-#undef SFREG
-#define SFREG 26
-#define DFREG 26
+#undef FREG
+#define FREG 26
#include "fop_template.c"
-#undef SFREG
-#undef DFREG
-#define SFREG 27
+#undef FREG
+#define FREG 27
#include "fop_template.c"
-#undef SFREG
-#define SFREG 28
-#define DFREG 28
+#undef FREG
+#define FREG 28
#include "fop_template.c"
-#undef SFREG
-#undef DFREG
-#define SFREG 29
+#undef FREG
+#define FREG 29
#include "fop_template.c"
-#undef SFREG
-#define SFREG 30
-#define DFREG 30
+#undef FREG
+#define FREG 30
#include "fop_template.c"
-#undef SFREG
-#undef DFREG
-#define SFREG 31
+#undef FREG
+#define FREG 31
#include "fop_template.c"
-#undef SFREG
+#undef FREG
#define FTN
#include "fop_template.c"
#undef FTN
-#endif
-
void op_dup_T0 (void)
{
T2 = T0;
@@ -325,6 +289,22 @@
#undef MEMSUFFIX
#endif
+/* Addresses computation */
+void op_addr_add (void)
+{
+/* For compatibility with 32-bit code, data reference in user mode
+ with Status_UX = 0 should be casted to 32-bit and sign extended.
+ See the MIPS64 PRA manual, section 4.10. */
+#ifdef TARGET_MIPS64
+ if ((env->CP0_Status & (1 << CP0St_UM)) &&
+ !(env->CP0_Status & (1 << CP0St_UX)))
+ T0 = (int64_t)(int32_t)(T0 + T1);
+ else
+#endif
+ T0 += T1;
+ RETURN();
+}
+
/* Arithmetic */
void op_add (void)
{
@@ -340,7 +320,7 @@
T0 = (int32_t)T0 + (int32_t)T1;
if (((tmp ^ T1 ^ (-1)) & (T0 ^ T1)) >> 31) {
/* operands of same sign, result different sign */
- CALL_FROM_TB1(do_raise_exception_direct, EXCP_OVERFLOW);
+ CALL_FROM_TB1(do_raise_exception, EXCP_OVERFLOW);
}
T0 = (int32_t)T0;
RETURN();
@@ -360,7 +340,7 @@
T0 = (int32_t)T0 - (int32_t)T1;
if (((tmp ^ T1) & (tmp ^ T0)) >> 31) {
/* operands of different sign, first operand and result different sign */
- CALL_FROM_TB1(do_raise_exception_direct, EXCP_OVERFLOW);
+ CALL_FROM_TB1(do_raise_exception, EXCP_OVERFLOW);
}
T0 = (int32_t)T0;
RETURN();
@@ -372,14 +352,22 @@
RETURN();
}
+#if HOST_LONG_BITS < 64
void op_div (void)
{
+ CALL_FROM_TB0(do_div);
+ RETURN();
+}
+#else
+void op_div (void)
+{
if (T1 != 0) {
- env->LO = (int32_t)((int32_t)T0 / (int32_t)T1);
- env->HI = (int32_t)((int32_t)T0 % (int32_t)T1);
+ env->LO = (int32_t)((int64_t)(int32_t)T0 / (int32_t)T1);
+ env->HI = (int32_t)((int64_t)(int32_t)T0 % (int32_t)T1);
}
RETURN();
}
+#endif
void op_divu (void)
{
@@ -390,7 +378,7 @@
RETURN();
}
-#ifdef MIPS_HAS_MIPS64
+#ifdef TARGET_MIPS64
/* Arithmetic */
void op_dadd (void)
{
@@ -406,7 +394,7 @@
T0 += T1;
if (((tmp ^ T1 ^ (-1)) & (T0 ^ T1)) >> 63) {
/* operands of same sign, result different sign */
- CALL_FROM_TB1(do_raise_exception_direct, EXCP_OVERFLOW);
+ CALL_FROM_TB1(do_raise_exception, EXCP_OVERFLOW);
}
RETURN();
}
@@ -425,7 +413,7 @@
T0 = (int64_t)T0 - (int64_t)T1;
if (((tmp ^ T1) & (tmp ^ T0)) >> 63) {
/* operands of different sign, first operand and result different sign */
- CALL_FROM_TB1(do_raise_exception_direct, EXCP_OVERFLOW);
+ CALL_FROM_TB1(do_raise_exception, EXCP_OVERFLOW);
}
RETURN();
}
@@ -436,7 +424,6 @@
RETURN();
}
-#if TARGET_LONG_BITS > HOST_LONG_BITS
/* Those might call libgcc functions. */
void op_ddiv (void)
{
@@ -444,21 +431,13 @@
RETURN();
}
+#if TARGET_LONG_BITS > HOST_LONG_BITS
void op_ddivu (void)
{
do_ddivu();
RETURN();
}
#else
-void op_ddiv (void)
-{
- if (T1 != 0) {
- env->LO = (int64_t)T0 / (int64_t)T1;
- env->HI = (int64_t)T0 % (int64_t)T1;
- }
- RETURN();
-}
-
void op_ddivu (void)
{
if (T1 != 0) {
@@ -468,7 +447,7 @@
RETURN();
}
#endif
-#endif /* MIPS_HAS_MIPS64 */
+#endif /* TARGET_MIPS64 */
/* Logical */
void op_and (void)
@@ -497,19 +476,19 @@
void op_sll (void)
{
- T0 = (int32_t)((uint32_t)T0 << (uint32_t)T1);
+ T0 = (int32_t)((uint32_t)T0 << T1);
RETURN();
}
void op_sra (void)
{
- T0 = (int32_t)((int32_t)T0 >> (uint32_t)T1);
+ T0 = (int32_t)((int32_t)T0 >> T1);
RETURN();
}
void op_srl (void)
{
- T0 = (int32_t)((uint32_t)T0 >> (uint32_t)T1);
+ T0 = (int32_t)((uint32_t)T0 >> T1);
RETURN();
}
@@ -518,10 +497,9 @@
target_ulong tmp;
if (T1) {
- tmp = (int32_t)((uint32_t)T0 << (0x20 - (uint32_t)T1));
- T0 = (int32_t)((uint32_t)T0 >> (uint32_t)T1) | tmp;
- } else
- T0 = T1;
+ tmp = (int32_t)((uint32_t)T0 << (0x20 - T1));
+ T0 = (int32_t)((uint32_t)T0 >> T1) | tmp;
+ }
RETURN();
}
@@ -590,7 +568,7 @@
RETURN();
}
-#ifdef MIPS_HAS_MIPS64
+#ifdef TARGET_MIPS64
#if TARGET_LONG_BITS > HOST_LONG_BITS
/* Those might call libgcc functions. */
@@ -711,8 +689,7 @@
if (T1) {
tmp = T0 << (0x40 - T1);
T0 = (T0 >> T1) | tmp;
- } else
- T0 = T1;
+ }
RETURN();
}
@@ -723,8 +700,7 @@
if (T1) {
tmp = T0 << (0x40 - (32 + T1));
T0 = (T0 >> (32 + T1)) | tmp;
- } else
- T0 = T1;
+ }
RETURN();
}
@@ -895,7 +871,7 @@
}
#endif /* TARGET_LONG_BITS > HOST_LONG_BITS */
-#ifdef MIPS_HAS_MIPS64
+#ifdef TARGET_MIPS64
void op_dmult (void)
{
CALL_FROM_TB0(do_dmult);
@@ -924,21 +900,19 @@
RETURN();
}
-#ifdef MIPS_USES_FPU
void op_movf (void)
{
if (!(env->fcr31 & PARAM1))
- env->gpr[PARAM2] = env->gpr[PARAM3];
+ T0 = T1;
RETURN();
}
void op_movt (void)
{
if (env->fcr31 & PARAM1)
- env->gpr[PARAM2] = env->gpr[PARAM3];
+ T0 = T1;
RETURN();
}
-#endif
/* Tests */
#define OP_COND(name, cond) \
@@ -1032,7 +1006,7 @@
/* CP0 functions */
void op_mfc0_index (void)
{
- T0 = (int32_t)(env->CP0_index);
+ T0 = env->CP0_Index;
RETURN();
}
@@ -1044,49 +1018,49 @@
void op_mfc0_entrylo0 (void)
{
- T0 = env->CP0_EntryLo0;
+ T0 = (int32_t)env->CP0_EntryLo0;
RETURN();
}
void op_mfc0_entrylo1 (void)
{
- T0 = env->CP0_EntryLo1;
+ T0 = (int32_t)env->CP0_EntryLo1;
RETURN();
}
void op_mfc0_context (void)
{
- T0 = env->CP0_Context;
+ T0 = (int32_t)env->CP0_Context;
RETURN();
}
void op_mfc0_pagemask (void)
{
- T0 = (int32_t)env->CP0_PageMask;
+ T0 = env->CP0_PageMask;
RETURN();
}
void op_mfc0_pagegrain (void)
{
- T0 = (int32_t)env->CP0_PageGrain;
+ T0 = env->CP0_PageGrain;
RETURN();
}
void op_mfc0_wired (void)
{
- T0 = (int32_t)env->CP0_Wired;
+ T0 = env->CP0_Wired;
RETURN();
}
void op_mfc0_hwrena (void)
{
- T0 = (int32_t)env->CP0_HWREna;
+ T0 = env->CP0_HWREna;
RETURN();
}
void op_mfc0_badvaddr (void)
{
- T0 = env->CP0_BadVAddr;
+ T0 = (int32_t)env->CP0_BadVAddr;
RETURN();
}
@@ -1098,55 +1072,55 @@
void op_mfc0_entryhi (void)
{
- T0 = env->CP0_EntryHi;
+ T0 = (int32_t)env->CP0_EntryHi;
RETURN();
}
void op_mfc0_compare (void)
{
- T0 = (int32_t)env->CP0_Compare;
+ T0 = env->CP0_Compare;
RETURN();
}
void op_mfc0_status (void)
{
- T0 = (int32_t)env->CP0_Status;
- if (env->hflags & MIPS_HFLAG_UM)
- T0 |= (1 << CP0St_UM);
- if (env->hflags & MIPS_HFLAG_ERL)
- T0 |= (1 << CP0St_ERL);
- if (env->hflags & MIPS_HFLAG_EXL)
- T0 |= (1 << CP0St_EXL);
+ T0 = env->CP0_Status;
RETURN();
}
void op_mfc0_intctl (void)
{
- T0 = (int32_t)env->CP0_IntCtl;
+ T0 = env->CP0_IntCtl;
RETURN();
}
void op_mfc0_srsctl (void)
{
- T0 = (int32_t)env->CP0_SRSCtl;
+ T0 = env->CP0_SRSCtl;
RETURN();
}
+void op_mfc0_srsmap (void)
+{
+ T0 = env->CP0_SRSMap;
+ RETURN();
+}
+
void op_mfc0_cause (void)
{
- T0 = (int32_t)env->CP0_Cause;
+ T0 = env->CP0_Cause;
RETURN();
}
void op_mfc0_epc (void)
{
- T0 = env->CP0_EPC;
+ T0 = (int32_t)env->CP0_EPC;
RETURN();
}
void op_mfc0_prid (void)
{
- T0 = (int32_t)env->CP0_PRid;
+ T0 = env->CP0_PRid;
RETURN();
}
@@ -1158,31 +1132,43 @@
void op_mfc0_config0 (void)
{
- T0 = (int32_t)env->CP0_Config0;
+ T0 = env->CP0_Config0;
RETURN();
}
void op_mfc0_config1 (void)
{
- T0 = (int32_t)env->CP0_Config1;
+ T0 = env->CP0_Config1;
RETURN();
}
void op_mfc0_config2 (void)
{
- T0 = (int32_t)env->CP0_Config2;
+ T0 = env->CP0_Config2;
RETURN();
}
void op_mfc0_config3 (void)
{
- T0 = (int32_t)env->CP0_Config3;
+ T0 = env->CP0_Config3;
RETURN();
}
+void op_mfc0_config6 (void)
+{
+ T0 = env->CP0_Config6;
+ RETURN();
+}
+
+void op_mfc0_config7 (void)
+{
+ T0 = env->CP0_Config7;
+ RETURN();
+}
+
void op_mfc0_lladdr (void)
{
- T0 = env->CP0_LLAddr >> 4;
+ T0 = (int32_t)env->CP0_LLAddr >> 4;
RETURN();
}
@@ -1194,13 +1180,13 @@
void op_mfc0_watchhi0 (void)
{
- T0 = (int32_t)env->CP0_WatchHi;
+ T0 = env->CP0_WatchHi;
RETURN();
}
void op_mfc0_xcontext (void)
{
- T0 = env->CP0_XContext;
+ T0 = (int32_t)env->CP0_XContext;
RETURN();
}
@@ -1212,7 +1198,7 @@
void op_mfc0_debug (void)
{
- T0 = (int32_t)env->CP0_Debug;
+ T0 = env->CP0_Debug;
if (env->hflags & MIPS_HFLAG_DM)
T0 |= 1 << CP0DB_DM;
RETURN();
@@ -1220,55 +1206,55 @@
void op_mfc0_depc (void)
{
- T0 = env->CP0_DEPC;
+ T0 = (int32_t)env->CP0_DEPC;
RETURN();
}
void op_mfc0_performance0 (void)
{
- T0 = (int32_t)env->CP0_Performance0;
+ T0 = env->CP0_Performance0;
RETURN();
}
void op_mfc0_taglo (void)
{
- T0 = (int32_t)env->CP0_TagLo;
+ T0 = env->CP0_TagLo;
RETURN();
}
void op_mfc0_datalo (void)
{
- T0 = (int32_t)env->CP0_DataLo;
+ T0 = env->CP0_DataLo;
RETURN();
}
void op_mfc0_taghi (void)
{
- T0 = (int32_t)env->CP0_TagHi;
+ T0 = env->CP0_TagHi;
RETURN();
}
void op_mfc0_datahi (void)
{
- T0 = (int32_t)env->CP0_DataHi;
+ T0 = env->CP0_DataHi;
RETURN();
}
void op_mfc0_errorepc (void)
{
- T0 = env->CP0_ErrorEPC;
+ T0 = (int32_t)env->CP0_ErrorEPC;
RETURN();
}
void op_mfc0_desave (void)
{
- T0 = (int32_t)env->CP0_DESAVE;
+ T0 = env->CP0_DESAVE;
RETURN();
}
void op_mtc0_index (void)
{
- env->CP0_index = (env->CP0_index & 0x80000000) | (T0 & (MIPS_TLB_NB - 1));
+ env->CP0_Index = (env->CP0_Index & 0x80000000) | (T0 % env->nb_tlb);
RETURN();
}
@@ -1276,7 +1262,7 @@
{
/* Large physaddr not implemented */
/* 1k pages not implemented */
- env->CP0_EntryLo0 = T0 & (int32_t)0x3FFFFFFF;
+ env->CP0_EntryLo0 = (int32_t)T0 & 0x3FFFFFFF;
RETURN();
}
@@ -1284,13 +1270,13 @@
{
/* Large physaddr not implemented */
/* 1k pages not implemented */
- env->CP0_EntryLo1 = T0 & (int32_t)0x3FFFFFFF;
+ env->CP0_EntryLo1 = (int32_t)T0 & 0x3FFFFFFF;
RETURN();
}
void op_mtc0_context (void)
{
- env->CP0_Context = (env->CP0_Context & ~0x007FFFFF) | (T0 & 0x007FFFF0);
+ env->CP0_Context = (env->CP0_Context & 0x007FFFFF) | (T0 & ~0x007FFFFF);
RETURN();
}
@@ -1312,7 +1298,7 @@
void op_mtc0_wired (void)
{
- env->CP0_Wired = T0 & (MIPS_TLB_NB - 1);
+ env->CP0_Wired = T0 % env->nb_tlb;
RETURN();
}
@@ -1334,7 +1320,7 @@
/* 1k pages not implemented */
/* Ignore MIPS64 TLB for now */
- val = T0 & (int32_t)0xFFFFE0FF;
+ val = (target_ulong)(int32_t)T0 & ~(target_ulong)0x1F00;
old = env->CP0_EntryHi;
env->CP0_EntryHi = val;
/* If the ASID changes, flush qemu's TLB. */
@@ -1351,45 +1337,30 @@
void op_mtc0_status (void)
{
- uint32_t val, old, mask;
+ uint32_t val, old;
+ uint32_t mask = env->Status_rw_bitmask;
- val = T0 & (int32_t)0xFA78FF01;
+ /* No reverse endianness, no MDMX/DSP, no 64bit ops,
+ no 64bit addressing implemented. */
+ val = (int32_t)T0 & mask;
old = env->CP0_Status;
- if (T0 & (1 << CP0St_UM))
+ if (!(val & (1 << CP0St_EXL)) &&
+ !(val & (1 << CP0St_ERL)) &&
+ !(env->hflags & MIPS_HFLAG_DM) &&
+ (val & (1 << CP0St_UM)))
env->hflags |= MIPS_HFLAG_UM;
- else
- env->hflags &= ~MIPS_HFLAG_UM;
- if (T0 & (1 << CP0St_ERL))
- env->hflags |= MIPS_HFLAG_ERL;
- else
- env->hflags &= ~MIPS_HFLAG_ERL;
- if (T0 & (1 << CP0St_EXL))
- env->hflags |= MIPS_HFLAG_EXL;
- else
- env->hflags &= ~MIPS_HFLAG_EXL;
- env->CP0_Status = val;
- /* If we unmasked an asserted IRQ, raise it */
- mask = 0x0000FF00;
- if (loglevel & CPU_LOG_TB_IN_ASM)
- CALL_FROM_TB2(do_mtc0_status_debug, old, val);
- if ((val & (1 << CP0St_IE)) && !(old & (1 << CP0St_IE)) &&
- !(env->hflags & MIPS_HFLAG_EXL) &&
- !(env->hflags & MIPS_HFLAG_ERL) &&
- !(env->hflags & MIPS_HFLAG_DM) &&
- (env->CP0_Status & env->CP0_Cause & mask)) {
- env->interrupt_request |= CPU_INTERRUPT_HARD;
- if (logfile)
- CALL_FROM_TB0(do_mtc0_status_irqraise_debug);
- } else if (!(val & (1 << CP0St_IE)) && (old & (1 << CP0St_IE))) {
- env->interrupt_request &= ~CPU_INTERRUPT_HARD;
- }
+ env->CP0_Status = (env->CP0_Status & ~mask) | val;
+ if (loglevel & CPU_LOG_EXEC)
+ CALL_FROM_TB2(do_mtc0_status_debug, old, val);
+ CALL_FROM_TB1(cpu_mips_update_irq, env);
RETURN();
}
void op_mtc0_intctl (void)
{
- /* vectored interrupts not implemented */
- env->CP0_IntCtl = 0;
+ /* vectored interrupts not implemented, timer on int 7,
+ no performance counters. */
+ env->CP0_IntCtl |= T0 & 0x000002e0;
RETURN();
}
@@ -1400,30 +1371,33 @@
RETURN();
}
+void op_mtc0_srsmap (void)
+{
+ /* shadow registers not implemented */
+ env->CP0_SRSMap = 0;
+ RETURN();
+}
+
void op_mtc0_cause (void)
{
- uint32_t val, old;
+ uint32_t mask = 0x00C00300;
- val = (env->CP0_Cause & 0xB000F87C) | (T0 & 0x00C00300);
- old = env->CP0_Cause;
- env->CP0_Cause = val;
-#if 0
- {
- int i, mask;
- /* Check if we ever asserted a software IRQ */
- for (i = 0; i < 2; i++) {
- mask = 0x100 << i;
- if ((val & mask) & !(old & mask))
- CALL_FROM_TB1(mips_set_irq, i);
- }
+ if ((env->CP0_Config0 & (0x7 << CP0C0_AR)) == (1 << CP0C0_AR))
+ mask |= 1 << CP0Ca_DC;
+
+ env->CP0_Cause = (env->CP0_Cause & ~mask) | (T0 & mask);
+
+ /* Handle the software interrupt as an hardware one, as they
+ are very similar */
+ if (T0 & CP0Ca_IP_mask) {
+ CALL_FROM_TB1(cpu_mips_update_irq, env);
}
-#endif
RETURN();
}
void op_mtc0_epc (void)
{
- env->CP0_EPC = T0;
+ env->CP0_EPC = (int32_t)T0;
RETURN();
}
@@ -1431,7 +1405,7 @@
{
/* vectored interrupts not implemented */
/* Multi-CPU not implemented */
- env->CP0_EBase = (int32_t)0x80000000 | (T0 & 0x3FFFF000);
+ env->CP0_EBase = 0x80000000 | (T0 & 0x3FFFF000);
RETURN();
}
@@ -1455,22 +1429,19 @@
void op_mtc0_watchlo0 (void)
{
- env->CP0_WatchLo = T0;
+ /* Watch exceptions for instructions, data loads, data stores
+ not implemented. */
+ env->CP0_WatchLo = (int32_t)(T0 & ~0x7);
RETURN();
}
void op_mtc0_watchhi0 (void)
{
- env->CP0_WatchHi = T0 & 0x40FF0FF8;
+ env->CP0_WatchHi = (T0 & 0x40FF0FF8);
+ env->CP0_WatchHi &= ~(env->CP0_WatchHi & T0 & 0x7);
RETURN();
}
-void op_mtc0_xcontext (void)
-{
- env->CP0_XContext = T0; /* XXX */
- RETURN();
-}
-
void op_mtc0_framemask (void)
{
env->CP0_Framemask = T0; /* XXX */
@@ -1489,7 +1460,7 @@
void op_mtc0_depc (void)
{
- env->CP0_DEPC = T0;
+ env->CP0_DEPC = (int32_t)T0;
RETURN();
}
@@ -1501,7 +1472,7 @@
void op_mtc0_taglo (void)
{
- env->CP0_TagLo = T0 & (int32_t)0xFFFFFCF6;
+ env->CP0_TagLo = T0 & 0xFFFFFCF6;
RETURN();
}
@@ -1525,7 +1496,7 @@
void op_mtc0_errorepc (void)
{
- env->CP0_ErrorEPC = T0;
+ env->CP0_ErrorEPC = (int32_t)T0;
RETURN();
}
@@ -1535,33 +1506,149 @@
RETURN();
}
-#ifdef MIPS_USES_FPU
+#ifdef TARGET_MIPS64
+void op_dmfc0_entrylo0 (void)
+{
+ T0 = env->CP0_EntryLo0;
+ RETURN();
+}
+void op_dmfc0_entrylo1 (void)
+{
+ T0 = env->CP0_EntryLo1;
+ RETURN();
+}
+
+void op_dmfc0_context (void)
+{
+ T0 = env->CP0_Context;
+ RETURN();
+}
+
+void op_dmfc0_badvaddr (void)
+{
+ T0 = env->CP0_BadVAddr;
+ RETURN();
+}
+
+void op_dmfc0_entryhi (void)
+{
+ T0 = env->CP0_EntryHi;
+ RETURN();
+}
+
+void op_dmfc0_epc (void)
+{
+ T0 = env->CP0_EPC;
+ RETURN();
+}
+
+void op_dmfc0_lladdr (void)
+{
+ T0 = env->CP0_LLAddr >> 4;
+ RETURN();
+}
+
+void op_dmfc0_watchlo0 (void)
+{
+ T0 = env->CP0_WatchLo;
+ RETURN();
+}
+
+void op_dmfc0_xcontext (void)
+{
+ T0 = env->CP0_XContext;
+ RETURN();
+}
+
+void op_dmfc0_depc (void)
+{
+ T0 = env->CP0_DEPC;
+ RETURN();
+}
+
+void op_dmfc0_errorepc (void)
+{
+ T0 = env->CP0_ErrorEPC;
+ RETURN();
+}
+
+void op_dmtc0_entrylo0 (void)
+{
+ /* Large physaddr not implemented */
+ /* 1k pages not implemented */
+ env->CP0_EntryLo0 = T0 & 0x3FFFFFFF;
+ RETURN();
+}
+
+void op_dmtc0_entrylo1 (void)
+{
+ /* Large physaddr not implemented */
+ /* 1k pages not implemented */
+ env->CP0_EntryLo1 = T0 & 0x3FFFFFFF;
+ RETURN();
+}
+
+void op_dmtc0_context (void)
+{
+ env->CP0_Context = (env->CP0_Context & 0x007FFFFF) | (T0 & ~0x007FFFFF);
+ RETURN();
+}
+
+void op_dmtc0_epc (void)
+{
+ env->CP0_EPC = T0;
+ RETURN();
+}
+
+void op_dmtc0_watchlo0 (void)
+{
+ /* Watch exceptions for instructions, data loads, data stores
+ not implemented. */
+ env->CP0_WatchLo = T0 & ~0x7;
+ RETURN();
+}
+
+void op_dmtc0_xcontext (void)
+{
+ env->CP0_XContext = (env->CP0_XContext & 0xffffffff) | (T0 & ~0xffffffff);
+ RETURN();
+}
+
+void op_dmtc0_depc (void)
+{
+ env->CP0_DEPC = T0;
+ RETURN();
+}
+
+void op_dmtc0_errorepc (void)
+{
+ env->CP0_ErrorEPC = T0;
+ RETURN();
+}
+#endif /* TARGET_MIPS64 */
+
+/* CP1 functions */
#if 0
# define DEBUG_FPU_STATE() CALL_FROM_TB1(dump_fpu, env)
#else
# define DEBUG_FPU_STATE() do { } while(0)
#endif
-void op_cp1_enabled(void)
+void op_cp0_enabled(void)
{
- if (!(env->CP0_Status & (1 << CP0St_CU1))) {
- CALL_FROM_TB2(do_raise_exception_err, EXCP_CpU, 1);
+ if (!(env->CP0_Status & (1 << CP0St_CU0)) &&
+ (env->hflags & MIPS_HFLAG_UM)) {
+ CALL_FROM_TB2(do_raise_exception_err, EXCP_CpU, 0);
}
RETURN();
}
-/* CP1 functions */
-void op_cfc1 (void)
+void op_cp1_enabled(void)
{
- if (T1 == 0) {
- T0 = env->fcr0;
+ if (!(env->CP0_Status & (1 << CP0St_CU1))) {
+ CALL_FROM_TB2(do_raise_exception_err, EXCP_CpU, 1);
}
- else {
- /* fetch fcr31, masking unused bits */
- T0 = env->fcr31 & 0x0183FFFF;
- }
- DEBUG_FPU_STATE();
RETURN();
}
@@ -1576,30 +1663,97 @@
#define RESTORE_ROUNDING_MODE \
set_float_rounding_mode(ieee_rm[env->fcr31 & 3], &env->fp_status)
-void op_ctc1 (void)
+inline char ieee_ex_to_mips(char xcpt)
{
- if (T1 == 0) {
- /* XXX should this throw an exception?
- * don't write to FCR0.
- * env->fcr0 = T0;
- */
- }
- else {
- /* store new fcr31, masking unused bits */
- env->fcr31 = T0 & 0x0183FFFF;
+ return (xcpt & float_flag_inexact) >> 5 |
+ (xcpt & float_flag_underflow) >> 3 |
+ (xcpt & float_flag_overflow) >> 1 |
+ (xcpt & float_flag_divbyzero) << 1 |
+ (xcpt & float_flag_invalid) << 4;
+}
- /* set rounding mode */
- RESTORE_ROUNDING_MODE;
+inline char mips_ex_to_ieee(char xcpt)
+{
+ return (xcpt & FP_INEXACT) << 5 |
+ (xcpt & FP_UNDERFLOW) << 3 |
+ (xcpt & FP_OVERFLOW) << 1 |
+ (xcpt & FP_DIV0) >> 1 |
+ (xcpt & FP_INVALID) >> 4;
+}
-#ifndef CONFIG_SOFTFLOAT
- /* no floating point exception for native float */
- SET_FP_ENABLE(env->fcr31, 0);
-#endif
+inline void update_fcr31(void)
+{
+ int tmp = ieee_ex_to_mips(get_float_exception_flags(&env->fp_status));
+
+ SET_FP_CAUSE(env->fcr31, tmp);
+ if (GET_FP_ENABLE(env->fcr31) & tmp)
+ CALL_FROM_TB1(do_raise_exception, EXCP_FPE);
+ else
+ UPDATE_FP_FLAGS(env->fcr31, tmp);
+}
+
+
+void op_cfc1 (void)
+{
+ switch (T1) {
+ case 0:
+ T0 = (int32_t)env->fcr0;
+ break;
+ case 25:
+ T0 = ((env->fcr31 >> 24) & 0xfe) | ((env->fcr31 >> 23) & 0x1);
+ break;
+ case 26:
+ T0 = env->fcr31 & 0x0003f07c;
+ break;
+ case 28:
+ T0 = (env->fcr31 & 0x00000f83) | ((env->fcr31 >> 22) & 0x4);
+ break;
+ default:
+ T0 = (int32_t)env->fcr31;
+ break;
}
DEBUG_FPU_STATE();
RETURN();
}
+void op_ctc1 (void)
+{
+ switch(T1) {
+ case 25:
+ if (T0 & 0xffffff00)
+ goto leave;
+ env->fcr31 = (env->fcr31 & 0x017fffff) | ((T0 & 0xfe) << 24) |
+ ((T0 & 0x1) << 23);
+ break;
+ case 26:
+ if (T0 & 0x007c0000)
+ goto leave;
+ env->fcr31 = (env->fcr31 & 0xfffc0f83) | (T0 & 0x0003f07c);
+ break;
+ case 28:
+ if (T0 & 0x007c0000)
+ goto leave;
+ env->fcr31 = (env->fcr31 & 0xfefff07c) | (T0 & 0x00000f83) |
+ ((T0 & 0x4) << 22);
+ break;
+ case 31:
+ if (T0 & 0x007c0000)
+ goto leave;
+ env->fcr31 = T0;
+ break;
+ default:
+ goto leave;
+ }
+ /* set rounding mode */
+ RESTORE_ROUNDING_MODE;
+ set_float_exception_flags(0, &env->fp_status);
+ if ((GET_FP_ENABLE(env->fcr31) | 0x20) & GET_FP_CAUSE(env->fcr31))
+ CALL_FROM_TB1(do_raise_exception, EXCP_FPE);
+ leave:
+ DEBUG_FPU_STATE();
+ RETURN();
+}
+
void op_mfc1 (void)
{
T0 = WT0;
@@ -1614,55 +1768,219 @@
RETURN();
}
+void op_dmfc1 (void)
+{
+ T0 = DT0;
+ DEBUG_FPU_STATE();
+ RETURN();
+}
+
+void op_dmtc1 (void)
+{
+ DT0 = T0;
+ DEBUG_FPU_STATE();
+ RETURN();
+}
+
+void op_mfhc1 (void)
+{
+ T0 = WTH0;
+ DEBUG_FPU_STATE();
+ RETURN();
+}
+
+void op_mthc1 (void)
+{
+ WTH0 = T0;
+ DEBUG_FPU_STATE();
+ RETURN();
+}
+
/* Float support.
Single precition routines have a "s" suffix, double precision a
- "d" suffix. */
+ "d" suffix, 32bit integer "w", 64bit integer "l", paired singe "ps",
+ paired single lowwer "pl", paired single upper "pu". */
#define FLOAT_OP(name, p) void OPPROTO op_float_##name##_##p(void)
FLOAT_OP(cvtd, s)
{
- FDT2 = float32_to_float64(WT0, &env->fp_status);
+ set_float_exception_flags(0, &env->fp_status);
+ FDT2 = float32_to_float64(FST0, &env->fp_status);
+ update_fcr31();
DEBUG_FPU_STATE();
RETURN();
}
FLOAT_OP(cvtd, w)
{
+ set_float_exception_flags(0, &env->fp_status);
FDT2 = int32_to_float64(WT0, &env->fp_status);
+ update_fcr31();
DEBUG_FPU_STATE();
RETURN();
}
+FLOAT_OP(cvtd, l)
+{
+ set_float_exception_flags(0, &env->fp_status);
+ FDT2 = int64_to_float64(DT0, &env->fp_status);
+ update_fcr31();
+ DEBUG_FPU_STATE();
+ RETURN();
+}
+FLOAT_OP(cvtl, d)
+{
+ set_float_exception_flags(0, &env->fp_status);
+ DT2 = float64_to_int64(FDT0, &env->fp_status);
+ update_fcr31();
+ if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+ DT2 = 0x7fffffffffffffffULL;
+ DEBUG_FPU_STATE();
+ RETURN();
+}
+FLOAT_OP(cvtl, s)
+{
+ set_float_exception_flags(0, &env->fp_status);
+ DT2 = float32_to_int64(FST0, &env->fp_status);
+ update_fcr31();
+ if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+ DT2 = 0x7fffffffffffffffULL;
+ DEBUG_FPU_STATE();
+ RETURN();
+}
+FLOAT_OP(cvtps, s)
+{
+ WT2 = WT0;
+ WTH2 = WT1;
+ DEBUG_FPU_STATE();
+ RETURN();
+}
+FLOAT_OP(cvtps, pw)
+{
+ set_float_exception_flags(0, &env->fp_status);
+ FST2 = int32_to_float32(WT0, &env->fp_status);
+ FSTH2 = int32_to_float32(WTH0, &env->fp_status);
+ update_fcr31();
+ DEBUG_FPU_STATE();
+ RETURN();
+}
+FLOAT_OP(cvtpw, ps)
+{
+ set_float_exception_flags(0, &env->fp_status);
+ WT2 = float32_to_int32(FST0, &env->fp_status);
+ WTH2 = float32_to_int32(FSTH0, &env->fp_status);
+ update_fcr31();
+ if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+ WT2 = 0x7fffffff;
+ DEBUG_FPU_STATE();
+ RETURN();
+}
FLOAT_OP(cvts, d)
{
+ set_float_exception_flags(0, &env->fp_status);
FST2 = float64_to_float32(FDT0, &env->fp_status);
+ update_fcr31();
DEBUG_FPU_STATE();
RETURN();
}
FLOAT_OP(cvts, w)
{
+ set_float_exception_flags(0, &env->fp_status);
FST2 = int32_to_float32(WT0, &env->fp_status);
+ update_fcr31();
DEBUG_FPU_STATE();
RETURN();
}
+FLOAT_OP(cvts, l)
+{
+ set_float_exception_flags(0, &env->fp_status);
+ FST2 = int64_to_float32(DT0, &env->fp_status);
+ update_fcr31();
+ DEBUG_FPU_STATE();
+ RETURN();
+}
+FLOAT_OP(cvts, pl)
+{
+ set_float_exception_flags(0, &env->fp_status);
+ WT2 = WT0;
+ update_fcr31();
+ DEBUG_FPU_STATE();
+ RETURN();
+}
+FLOAT_OP(cvts, pu)
+{
+ set_float_exception_flags(0, &env->fp_status);
+ WT2 = WTH0;
+ update_fcr31();
+ DEBUG_FPU_STATE();
+ RETURN();
+}
FLOAT_OP(cvtw, s)
{
+ set_float_exception_flags(0, &env->fp_status);
WT2 = float32_to_int32(FST0, &env->fp_status);
+ update_fcr31();
+ if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+ WT2 = 0x7fffffff;
DEBUG_FPU_STATE();
RETURN();
}
FLOAT_OP(cvtw, d)
{
+ set_float_exception_flags(0, &env->fp_status);
WT2 = float64_to_int32(FDT0, &env->fp_status);
+ update_fcr31();
+ if (GET_FP_CAUSE(env->fcr31) & (FP_OVERFLOW | FP_INVALID))
+ WT2 = 0x7fffffff;
DEBUG_FPU_STATE();
RETURN();
}
+FLOAT_OP(pll, ps)
+{
+ DT2 = ((uint64_t)WT0 << 32) | WT1;
+ DEBUG_FPU_STATE();
+ RETURN();
+}
+FLOAT_OP(plu, ps)
+{
+ DT2 = ((uint64_t)WT0 << 32) | WTH1;
+ DEBUG_FPU_STATE();
+ RETURN();
+}
+FLOAT_OP(pul, ps)
+{
+ DT2 = ((uint64_t)WTH0 << 32) | WT1;
+ DEBUG_FPU_STATE();
+ RETURN();
+}
+FLOAT_OP(puu, ps)
+{
+ DT2 = ((uint64_t)WTH0 << 32) | WTH1;
+ DEBUG_FPU_STATE();
+ RETURN();
+}
+
+FLOAT_OP(roundl, d)
+{
+ set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
+ DT2 = float64_round_to_int(FDT0, &env->fp_status);
+ RESTORE_ROUNDING_MODE;
+ DEBUG_FPU_STATE();
+ RETURN();
+}
+FLOAT_OP(roundl, s)
+{
+ set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
+ DT2 = float32_round_to_int(FST0, &env->fp_status);
+ RESTORE_ROUNDING_MODE;
+ DEBUG_FPU_STATE();
+ RETURN();
+}
FLOAT_OP(roundw, d)
{
set_float_rounding_mode(float_round_nearest_even, &env->fp_status);
WT2 = float64_round_to_int(FDT0, &env->fp_status);
RESTORE_ROUNDING_MODE;
-
DEBUG_FPU_STATE();
RETURN();
}
@@ -1675,6 +1993,18 @@
RETURN();
}
+FLOAT_OP(truncl, d)
+{
+ DT2 = float64_to_int64_round_to_zero(FDT0, &env->fp_status);
+ DEBUG_FPU_STATE();
+ RETURN();
+}
+FLOAT_OP(truncl, s)
+{
+ DT2 = float32_to_int64_round_to_zero(FST0, &env->fp_status);
+ DEBUG_FPU_STATE();
+ RETURN();
+}
FLOAT_OP(truncw, d)
{
WT2 = float64_to_int32_round_to_zero(FDT0, &env->fp_status);
@@ -1688,12 +2018,27 @@
RETURN();
}
+FLOAT_OP(ceill, d)
+{
+ set_float_rounding_mode(float_round_up, &env->fp_status);
+ DT2 = float64_round_to_int(FDT0, &env->fp_status);
+ RESTORE_ROUNDING_MODE;
+ DEBUG_FPU_STATE();
+ RETURN();
+}
+FLOAT_OP(ceill, s)
+{
+ set_float_rounding_mode(float_round_up, &env->fp_status);
+ DT2 = float32_round_to_int(FST0, &env->fp_status);
+ RESTORE_ROUNDING_MODE;
+ DEBUG_FPU_STATE();
+ RETURN();
+}
FLOAT_OP(ceilw, d)
{
set_float_rounding_mode(float_round_up, &env->fp_status);
WT2 = float64_round_to_int(FDT0, &env->fp_status);
RESTORE_ROUNDING_MODE;
-
DEBUG_FPU_STATE();
RETURN();
}
@@ -1706,12 +2051,27 @@
RETURN();
}
+FLOAT_OP(floorl, d)
+{
+ set_float_rounding_mode(float_round_down, &env->fp_status);
+ DT2 = float64_round_to_int(FDT0, &env->fp_status);
+ RESTORE_ROUNDING_MODE;
+ DEBUG_FPU_STATE();
+ RETURN();
+}
+FLOAT_OP(floorl, s)
+{
+ set_float_rounding_mode(float_round_down, &env->fp_status);
+ DT2 = float32_round_to_int(FST0, &env->fp_status);
+ RESTORE_ROUNDING_MODE;
+ DEBUG_FPU_STATE();
+ RETURN();
+}
FLOAT_OP(floorw, d)
{
set_float_rounding_mode(float_round_down, &env->fp_status);
WT2 = float64_round_to_int(FDT0, &env->fp_status);
RESTORE_ROUNDING_MODE;
-
DEBUG_FPU_STATE();
RETURN();
}
@@ -1724,17 +2084,122 @@
RETURN();
}
+FLOAT_OP(movf, d)
+{
+ if (!(env->fcr31 & PARAM1))
+ DT2 = DT0;
+ DEBUG_FPU_STATE();
+ RETURN();
+}
+FLOAT_OP(movf, s)
+{
+ if (!(env->fcr31 & PARAM1))
+ WT2 = WT0;
+ DEBUG_FPU_STATE();
+ RETURN();
+}
+FLOAT_OP(movf, ps)
+{
+ if (!(env->fcr31 & PARAM1)) {
+ WT2 = WT0;
+ WTH2 = WTH0;
+ }
+ DEBUG_FPU_STATE();
+ RETURN();
+}
+FLOAT_OP(movt, d)
+{
+ if (env->fcr31 & PARAM1)
+ DT2 = DT0;
+ DEBUG_FPU_STATE();
+ RETURN();
+}
+FLOAT_OP(movt, s)
+{
+ if (env->fcr31 & PARAM1)
+ WT2 = WT0;
+ DEBUG_FPU_STATE();
+ RETURN();
+}
+FLOAT_OP(movt, ps)
+{
+ if (env->fcr31 & PARAM1) {
+ WT2 = WT0;
+ WTH2 = WTH0;
+ }
+ DEBUG_FPU_STATE();
+ RETURN();
+}
+FLOAT_OP(movz, d)
+{
+ if (!T0)
+ DT2 = DT0;
+ DEBUG_FPU_STATE();
+ RETURN();
+}
+FLOAT_OP(movz, s)
+{
+ if (!T0)
+ WT2 = WT0;
+ DEBUG_FPU_STATE();
+ RETURN();
+}
+FLOAT_OP(movz, ps)
+{
+ if (!T0) {
+ WT2 = WT0;
+ WTH2 = WTH0;
+ }
+ DEBUG_FPU_STATE();
+ RETURN();
+}
+FLOAT_OP(movn, d)
+{
+ if (T0)
+ DT2 = DT0;
+ DEBUG_FPU_STATE();
+ RETURN();
+}
+FLOAT_OP(movn, s)
+{
+ if (T0)
+ WT2 = WT0;
+ DEBUG_FPU_STATE();
+ RETURN();
+}
+FLOAT_OP(movn, ps)
+{
+ if (T0) {
+ WT2 = WT0;
+ WTH2 = WTH0;
+ }
+ DEBUG_FPU_STATE();
+ RETURN();
+}
+
/* binary operations */
#define FLOAT_BINOP(name) \
FLOAT_OP(name, d) \
{ \
+ set_float_exception_flags(0, &env->fp_status); \
FDT2 = float64_ ## name (FDT0, FDT1, &env->fp_status); \
+ update_fcr31(); \
DEBUG_FPU_STATE(); \
} \
FLOAT_OP(name, s) \
{ \
+ set_float_exception_flags(0, &env->fp_status); \
FST2 = float32_ ## name (FST0, FST1, &env->fp_status); \
+ update_fcr31(); \
DEBUG_FPU_STATE(); \
+} \
+FLOAT_OP(name, ps) \
+{ \
+ set_float_exception_flags(0, &env->fp_status); \
+ FST2 = float32_ ## name (FST0, FST1, &env->fp_status); \
+ FSTH2 = float32_ ## name (FSTH0, FSTH1, &env->fp_status); \
+ update_fcr31(); \
+ DEBUG_FPU_STATE(); \
}
FLOAT_BINOP(add)
FLOAT_BINOP(sub)
@@ -1742,6 +2207,32 @@
FLOAT_BINOP(div)
#undef FLOAT_BINOP
+/* ternary operations */
+#define FLOAT_TERNOP(name1, name2) \
+FLOAT_OP(name1 ## name2, d) \
+{ \
+ FDT0 = float64_ ## name1 (FDT0, FDT1, &env->fp_status); \
+ FDT2 = float64_ ## name2 (FDT0, FDT2, &env->fp_status); \
+ DEBUG_FPU_STATE(); \
+} \
+FLOAT_OP(name1 ## name2, s) \
+{ \
+ FST0 = float32_ ## name1 (FST0, FST1, &env->fp_status); \
+ FST2 = float32_ ## name2 (FST0, FST2, &env->fp_status); \
+ DEBUG_FPU_STATE(); \
+} \
+FLOAT_OP(name1 ## name2, ps) \
+{ \
+ FST0 = float32_ ## name1 (FST0, FST1, &env->fp_status); \
+ FSTH0 = float32_ ## name1 (FSTH0, FSTH1, &env->fp_status); \
+ FST2 = float32_ ## name2 (FST0, FST2, &env->fp_status); \
+ FSTH2 = float32_ ## name2 (FSTH0, FSTH2, &env->fp_status); \
+ DEBUG_FPU_STATE(); \
+}
+FLOAT_TERNOP(mul, add)
+FLOAT_TERNOP(mul, sub)
+#undef FLOAT_TERNOP
+
/* unary operations, modifying fp status */
#define FLOAT_UNOP(name) \
FLOAT_OP(name, d) \
@@ -1753,6 +2244,12 @@
{ \
FST2 = float32_ ## name(FST0, &env->fp_status); \
DEBUG_FPU_STATE(); \
+} \
+FLOAT_OP(name, ps) \
+{ \
+ FST2 = float32_ ## name(FST0, &env->fp_status); \
+ FSTH2 = float32_ ## name(FSTH0, &env->fp_status); \
+ DEBUG_FPU_STATE(); \
}
FLOAT_UNOP(sqrt)
#undef FLOAT_UNOP
@@ -1768,6 +2265,12 @@
{ \
FST2 = float32_ ## name(FST0); \
DEBUG_FPU_STATE(); \
+} \
+FLOAT_OP(name, ps) \
+{ \
+ FST2 = float32_ ## name(FST0); \
+ FSTH2 = float32_ ## name(FSTH0); \
+ DEBUG_FPU_STATE(); \
}
FLOAT_UNOP(abs)
FLOAT_UNOP(chs)
@@ -1785,6 +2288,35 @@
DEBUG_FPU_STATE();
RETURN();
}
+FLOAT_OP(mov, ps)
+{
+ FST2 = FST0;
+ FSTH2 = FSTH0;
+ DEBUG_FPU_STATE();
+ RETURN();
+}
+FLOAT_OP(alnv, ps)
+{
+ switch (T0 & 0x7) {
+ case 0:
+ FST2 = FST0;
+ FSTH2 = FSTH0;
+ break;
+ case 4:
+#ifdef TARGET_WORDS_BIGENDIAN
+ FSTH2 = FST0;
+ FST2 = FSTH1;
+#else
+ FSTH2 = FST1;
+ FST2 = FSTH0;
+#endif
+ break;
+ default: /* unpredictable */
+ break;
+ }
+ DEBUG_FPU_STATE();
+ RETURN();
+}
#ifdef CONFIG_SOFTFLOAT
#define clear_invalid() do { \
@@ -1798,100 +2330,203 @@
extern void dump_fpu_s(CPUState *env);
-#define FOP_COND(fmt, op, sig, cond) \
-void op_cmp_ ## fmt ## _ ## op (void) \
+#define FOP_COND_D(op, cond) \
+void op_cmp_d_ ## op (void) \
{ \
- if (cond) \
- SET_FP_COND(env->fcr31); \
+ int c = cond; \
+ update_fcr31(); \
+ if (c) \
+ SET_FP_COND(PARAM1, env); \
else \
- CLEAR_FP_COND(env->fcr31); \
- if (!sig) \
- clear_invalid(); \
- /*CALL_FROM_TB1(dump_fpu_s, env);*/ \
+ CLEAR_FP_COND(PARAM1, env); \
DEBUG_FPU_STATE(); \
RETURN(); \
}
-int float64_is_unordered(float64 a, float64 b STATUS_PARAM)
+int float64_is_unordered(int sig, float64 a, float64 b STATUS_PARAM)
{
- if (float64_is_nan(a) || float64_is_nan(b)) {
+ if (float64_is_signaling_nan(a) ||
+ float64_is_signaling_nan(b) ||
+ (sig && (float64_is_nan(a) || float64_is_nan(b)))) {
float_raise(float_flag_invalid, status);
return 1;
- }
- else {
+ } else if (float64_is_nan(a) || float64_is_nan(b)) {
+ return 1;
+ } else {
return 0;
}
}
-FOP_COND(d, f, 0, 0)
-FOP_COND(d, un, 0, float64_is_unordered(FDT1, FDT0, &env->fp_status))
-FOP_COND(d, eq, 0, float64_eq(FDT0, FDT1, &env->fp_status))
-FOP_COND(d, ueq, 0, float64_is_unordered(FDT1, FDT0, &env->fp_status) || float64_eq(FDT0, FDT1, &env->fp_status))
-FOP_COND(d, olt, 0, float64_lt(FDT0, FDT1, &env->fp_status))
-FOP_COND(d, ult, 0, float64_is_unordered(FDT1, FDT0, &env->fp_status) || float64_lt(FDT0, FDT1, &env->fp_status))
-FOP_COND(d, ole, 0, float64_le(FDT0, FDT1, &env->fp_status))
-FOP_COND(d, ule, 0, float64_is_unordered(FDT1, FDT0, &env->fp_status) || float64_le(FDT0, FDT1, &env->fp_status))
/* NOTE: the comma operator will make "cond" to eval to false,
- * but float*_is_unordered() is still called
- */
-FOP_COND(d, sf, 1, (float64_is_unordered(FDT0, FDT1, &env->fp_status), 0))
-FOP_COND(d, ngle,1, float64_is_unordered(FDT1, FDT0, &env->fp_status))
-FOP_COND(d, seq, 1, float64_eq(FDT0, FDT1, &env->fp_status))
-FOP_COND(d, ngl, 1, float64_is_unordered(FDT1, FDT0, &env->fp_status) || float64_eq(FDT0, FDT1, &env->fp_status))
-FOP_COND(d, lt, 1, float64_lt(FDT0, FDT1, &env->fp_status))
-FOP_COND(d, nge, 1, float64_is_unordered(FDT1, FDT0, &env->fp_status) || float64_lt(FDT0, FDT1, &env->fp_status))
-FOP_COND(d, le, 1, float64_le(FDT0, FDT1, &env->fp_status))
-FOP_COND(d, ngt, 1, float64_is_unordered(FDT1, FDT0, &env->fp_status) || float64_le(FDT0, FDT1, &env->fp_status))
+ * but float*_is_unordered() is still called. */
+FOP_COND_D(f, (float64_is_unordered(0, FDT1, FDT0, &env->fp_status), 0))
+FOP_COND_D(un, float64_is_unordered(0, FDT1, FDT0, &env->fp_status))
+FOP_COND_D(eq, !float64_is_unordered(0, FDT1, FDT0, &env->fp_status) && float64_eq(FDT0, FDT1, &env->fp_status))
+FOP_COND_D(ueq, float64_is_unordered(0, FDT1, FDT0, &env->fp_status) || float64_eq(FDT0, FDT1, &env->fp_status))
+FOP_COND_D(olt, !float64_is_unordered(0, FDT1, FDT0, &env->fp_status) && float64_lt(FDT0, FDT1, &env->fp_status))
+FOP_COND_D(ult, float64_is_unordered(0, FDT1, FDT0, &env->fp_status) || float64_lt(FDT0, FDT1, &env->fp_status))
+FOP_COND_D(ole, !float64_is_unordered(0, FDT1, FDT0, &env->fp_status) && float64_le(FDT0, FDT1, &env->fp_status))
+FOP_COND_D(ule, float64_is_unordered(0, FDT1, FDT0, &env->fp_status) || float64_le(FDT0, FDT1, &env->fp_status))
+/* NOTE: the comma operator will make "cond" to eval to false,
+ * but float*_is_unordered() is still called. */
+FOP_COND_D(sf, (float64_is_unordered(1, FDT1, FDT0, &env->fp_status), 0))
+FOP_COND_D(ngle,float64_is_unordered(1, FDT1, FDT0, &env->fp_status))
+FOP_COND_D(seq, !float64_is_unordered(1, FDT1, FDT0, &env->fp_status) && float64_eq(FDT0, FDT1, &env->fp_status))
+FOP_COND_D(ngl, float64_is_unordered(1, FDT1, FDT0, &env->fp_status) || float64_eq(FDT0, FDT1, &env->fp_status))
+FOP_COND_D(lt, !float64_is_unordered(1, FDT1, FDT0, &env->fp_status) && float64_lt(FDT0, FDT1, &env->fp_status))
+FOP_COND_D(nge, float64_is_unordered(1, FDT1, FDT0, &env->fp_status) || float64_lt(FDT0, FDT1, &env->fp_status))
+FOP_COND_D(le, !float64_is_unordered(1, FDT1, FDT0, &env->fp_status) && float64_le(FDT0, FDT1, &env->fp_status))
+FOP_COND_D(ngt, float64_is_unordered(1, FDT1, FDT0, &env->fp_status) || float64_le(FDT0, FDT1, &env->fp_status))
-flag float32_is_unordered(float32 a, float32 b STATUS_PARAM)
+#define FOP_COND_S(op, cond) \
+void op_cmp_s_ ## op (void) \
+{ \
+ int c = cond; \
+ update_fcr31(); \
+ if (c) \
+ SET_FP_COND(PARAM1, env); \
+ else \
+ CLEAR_FP_COND(PARAM1, env); \
+ DEBUG_FPU_STATE(); \
+ RETURN(); \
+}
+
+flag float32_is_unordered(int sig, float32 a, float32 b STATUS_PARAM)
{
- extern flag float32_is_nan( float32 a );
- if (float32_is_nan(a) || float32_is_nan(b)) {
+ extern flag float32_is_nan(float32 a);
+ if (float32_is_signaling_nan(a) ||
+ float32_is_signaling_nan(b) ||
+ (sig && (float32_is_nan(a) || float32_is_nan(b)))) {
float_raise(float_flag_invalid, status);
return 1;
- }
- else {
+ } else if (float32_is_nan(a) || float32_is_nan(b)) {
+ return 1;
+ } else {
return 0;
}
}
/* NOTE: the comma operator will make "cond" to eval to false,
- * but float*_is_unordered() is still called
- */
-FOP_COND(s, f, 0, 0)
-FOP_COND(s, un, 0, float32_is_unordered(FST1, FST0, &env->fp_status))
-FOP_COND(s, eq, 0, float32_eq(FST0, FST1, &env->fp_status))
-FOP_COND(s, ueq, 0, float32_is_unordered(FST1, FST0, &env->fp_status) || float32_eq(FST0, FST1, &env->fp_status))
-FOP_COND(s, olt, 0, float32_lt(FST0, FST1, &env->fp_status))
-FOP_COND(s, ult, 0, float32_is_unordered(FST1, FST0, &env->fp_status) || float32_lt(FST0, FST1, &env->fp_status))
-FOP_COND(s, ole, 0, float32_le(FST0, FST1, &env->fp_status))
-FOP_COND(s, ule, 0, float32_is_unordered(FST1, FST0, &env->fp_status) || float32_le(FST0, FST1, &env->fp_status))
+ * but float*_is_unordered() is still called. */
+FOP_COND_S(f, (float32_is_unordered(0, FST1, FST0, &env->fp_status), 0))
+FOP_COND_S(un, float32_is_unordered(0, FST1, FST0, &env->fp_status))
+FOP_COND_S(eq, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_eq(FST0, FST1, &env->fp_status))
+FOP_COND_S(ueq, float32_is_unordered(0, FST1, FST0, &env->fp_status) || float32_eq(FST0, FST1, &env->fp_status))
+FOP_COND_S(olt, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_lt(FST0, FST1, &env->fp_status))
+FOP_COND_S(ult, float32_is_unordered(0, FST1, FST0, &env->fp_status) || float32_lt(FST0, FST1, &env->fp_status))
+FOP_COND_S(ole, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_le(FST0, FST1, &env->fp_status))
+FOP_COND_S(ule, float32_is_unordered(0, FST1, FST0, &env->fp_status) || float32_le(FST0, FST1, &env->fp_status))
/* NOTE: the comma operator will make "cond" to eval to false,
- * but float*_is_unordered() is still called
- */
-FOP_COND(s, sf, 1, (float32_is_unordered(FST0, FST1, &env->fp_status), 0))
-FOP_COND(s, ngle,1, float32_is_unordered(FST1, FST0, &env->fp_status))
-FOP_COND(s, seq, 1, float32_eq(FST0, FST1, &env->fp_status))
-FOP_COND(s, ngl, 1, float32_is_unordered(FST1, FST0, &env->fp_status) || float32_eq(FST0, FST1, &env->fp_status))
-FOP_COND(s, lt, 1, float32_lt(FST0, FST1, &env->fp_status))
-FOP_COND(s, nge, 1, float32_is_unordered(FST1, FST0, &env->fp_status) || float32_lt(FST0, FST1, &env->fp_status))
-FOP_COND(s, le, 1, float32_le(FST0, FST1, &env->fp_status))
-FOP_COND(s, ngt, 1, float32_is_unordered(FST1, FST0, &env->fp_status) || float32_le(FST0, FST1, &env->fp_status))
+ * but float*_is_unordered() is still called. */
+FOP_COND_S(sf, (float32_is_unordered(1, FST1, FST0, &env->fp_status), 0))
+FOP_COND_S(ngle,float32_is_unordered(1, FST1, FST0, &env->fp_status))
+FOP_COND_S(seq, !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_eq(FST0, FST1, &env->fp_status))
+FOP_COND_S(ngl, float32_is_unordered(1, FST1, FST0, &env->fp_status) || float32_eq(FST0, FST1, &env->fp_status))
+FOP_COND_S(lt, !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_lt(FST0, FST1, &env->fp_status))
+FOP_COND_S(nge, float32_is_unordered(1, FST1, FST0, &env->fp_status) || float32_lt(FST0, FST1, &env->fp_status))
+FOP_COND_S(le, !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_le(FST0, FST1, &env->fp_status))
+FOP_COND_S(ngt, float32_is_unordered(1, FST1, FST0, &env->fp_status) || float32_le(FST0, FST1, &env->fp_status))
+#define FOP_COND_PS(op, condl, condh) \
+void op_cmp_ps_ ## op (void) \
+{ \
+ int cl = condl; \
+ int ch = condh; \
+ update_fcr31(); \
+ if (cl) \
+ SET_FP_COND(PARAM1, env); \
+ else \
+ CLEAR_FP_COND(PARAM1, env); \
+ if (ch) \
+ SET_FP_COND(PARAM1 + 1, env); \
+ else \
+ CLEAR_FP_COND(PARAM1 + 1, env); \
+ DEBUG_FPU_STATE(); \
+ RETURN(); \
+}
+
+/* NOTE: the comma operator will make "cond" to eval to false,
+ * but float*_is_unordered() is still called. */
+FOP_COND_PS(f, (float32_is_unordered(0, FST1, FST0, &env->fp_status), 0),
+ (float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status), 0))
+FOP_COND_PS(un, float32_is_unordered(0, FST1, FST0, &env->fp_status),
+ float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status))
+FOP_COND_PS(eq, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_eq(FST0, FST1, &env->fp_status),
+ !float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) && float32_eq(FSTH0, FSTH1, &env->fp_status))
+FOP_COND_PS(ueq, float32_is_unordered(0, FST1, FST0, &env->fp_status) || float32_eq(FST0, FST1, &env->fp_status),
+ float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) || float32_eq(FSTH0, FSTH1, &env->fp_status))
+FOP_COND_PS(olt, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_lt(FST0, FST1, &env->fp_status),
+ !float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) && float32_lt(FSTH0, FSTH1, &env->fp_status))
+FOP_COND_PS(ult, float32_is_unordered(0, FST1, FST0, &env->fp_status) || float32_lt(FST0, FST1, &env->fp_status),
+ float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) || float32_lt(FSTH0, FSTH1, &env->fp_status))
+FOP_COND_PS(ole, !float32_is_unordered(0, FST1, FST0, &env->fp_status) && float32_le(FST0, FST1, &env->fp_status),
+ !float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) && float32_le(FSTH0, FSTH1, &env->fp_status))
+FOP_COND_PS(ule, float32_is_unordered(0, FST1, FST0, &env->fp_status) || float32_le(FST0, FST1, &env->fp_status),
+ float32_is_unordered(0, FSTH1, FSTH0, &env->fp_status) || float32_le(FSTH0, FSTH1, &env->fp_status))
+/* NOTE: the comma operator will make "cond" to eval to false,
+ * but float*_is_unordered() is still called. */
+FOP_COND_PS(sf, (float32_is_unordered(1, FST1, FST0, &env->fp_status), 0),
+ (float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status), 0))
+FOP_COND_PS(ngle,float32_is_unordered(1, FST1, FST0, &env->fp_status),
+ float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status))
+FOP_COND_PS(seq, !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_eq(FST0, FST1, &env->fp_status),
+ !float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) && float32_eq(FSTH0, FSTH1, &env->fp_status))
+FOP_COND_PS(ngl, float32_is_unordered(1, FST1, FST0, &env->fp_status) || float32_eq(FST0, FST1, &env->fp_status),
+ float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) || float32_eq(FSTH0, FSTH1, &env->fp_status))
+FOP_COND_PS(lt, !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_lt(FST0, FST1, &env->fp_status),
+ !float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) && float32_lt(FSTH0, FSTH1, &env->fp_status))
+FOP_COND_PS(nge, float32_is_unordered(1, FST1, FST0, &env->fp_status) || float32_lt(FST0, FST1, &env->fp_status),
+ float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) || float32_lt(FSTH0, FSTH1, &env->fp_status))
+FOP_COND_PS(le, !float32_is_unordered(1, FST1, FST0, &env->fp_status) && float32_le(FST0, FST1, &env->fp_status),
+ !float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) && float32_le(FSTH0, FSTH1, &env->fp_status))
+FOP_COND_PS(ngt, float32_is_unordered(1, FST1, FST0, &env->fp_status) || float32_le(FST0, FST1, &env->fp_status),
+ float32_is_unordered(1, FSTH1, FSTH0, &env->fp_status) || float32_le(FSTH0, FSTH1, &env->fp_status))
+
void op_bc1f (void)
{
- T0 = ! IS_FP_COND_SET(env->fcr31);
+ T0 = !IS_FP_COND_SET(PARAM1, env);
DEBUG_FPU_STATE();
RETURN();
}
+void op_bc1fany2 (void)
+{
+ T0 = (!IS_FP_COND_SET(PARAM1, env) ||
+ !IS_FP_COND_SET(PARAM1 + 1, env));
+ DEBUG_FPU_STATE();
+ RETURN();
+}
+void op_bc1fany4 (void)
+{
+ T0 = (!IS_FP_COND_SET(PARAM1, env) ||
+ !IS_FP_COND_SET(PARAM1 + 1, env) ||
+ !IS_FP_COND_SET(PARAM1 + 2, env) ||
+ !IS_FP_COND_SET(PARAM1 + 3, env));
+ DEBUG_FPU_STATE();
+ RETURN();
+}
void op_bc1t (void)
{
- T0 = IS_FP_COND_SET(env->fcr31);
+ T0 = IS_FP_COND_SET(PARAM1, env);
DEBUG_FPU_STATE();
RETURN();
}
-#endif /* MIPS_USES_FPU */
+void op_bc1tany2 (void)
+{
+ T0 = (IS_FP_COND_SET(PARAM1, env) ||
+ IS_FP_COND_SET(PARAM1 + 1, env));
+ DEBUG_FPU_STATE();
+ RETURN();
+}
+void op_bc1tany4 (void)
+{
+ T0 = (IS_FP_COND_SET(PARAM1, env) ||
+ IS_FP_COND_SET(PARAM1 + 1, env) ||
+ IS_FP_COND_SET(PARAM1 + 2, env) ||
+ IS_FP_COND_SET(PARAM1 + 3, env));
+ DEBUG_FPU_STATE();
+ RETURN();
+}
#if defined(MIPS_USES_R4K_TLB)
void op_tlbwi (void)
@@ -1920,6 +2555,13 @@
#endif
/* Specials */
+#if defined (CONFIG_USER_ONLY)
+void op_tls_value (void)
+{
+ T0 = env->tls_value;
+}
+#endif
+
void op_pmon (void)
{
CALL_FROM_TB1(do_pmon, PARAM1);
@@ -1928,43 +2570,24 @@
void op_di (void)
{
- uint32_t val;
-
T0 = env->CP0_Status;
- val = T0 & ~(1 << CP0St_IE);
- if (val != T0) {
- env->interrupt_request &= ~CPU_INTERRUPT_HARD;
- env->CP0_Status = val;
- }
+ env->CP0_Status = T0 & ~(1 << CP0St_IE);
+ CALL_FROM_TB1(cpu_mips_update_irq, env);
RETURN();
}
void op_ei (void)
{
- uint32_t val;
-
T0 = env->CP0_Status;
- val = T0 | (1 << CP0St_IE);
- if (val != T0) {
- const uint32_t mask = 0x0000FF00;
-
- env->CP0_Status = val;
- if (!(env->hflags & MIPS_HFLAG_EXL) &&
- !(env->hflags & MIPS_HFLAG_ERL) &&
- !(env->hflags & MIPS_HFLAG_DM) &&
- (env->CP0_Status & env->CP0_Cause & mask)) {
- env->interrupt_request |= CPU_INTERRUPT_HARD;
- if (logfile)
- CALL_FROM_TB0(do_mtc0_status_irqraise_debug);
- }
- }
+ env->CP0_Status = T0 | (1 << CP0St_IE);
+ CALL_FROM_TB1(cpu_mips_update_irq, env);
RETURN();
}
void op_trap (void)
{
if (T0) {
- CALL_FROM_TB1(do_raise_exception_direct, EXCP_TRAP);
+ CALL_FROM_TB1(do_raise_exception, EXCP_TRAP);
}
RETURN();
}
@@ -1981,63 +2604,88 @@
RETURN();
}
-void debug_eret (void);
+void debug_pre_eret (void);
+void debug_post_eret (void);
void op_eret (void)
{
- CALL_FROM_TB0(debug_eret);
- if (env->hflags & MIPS_HFLAG_ERL) {
+ if (loglevel & CPU_LOG_EXEC)
+ CALL_FROM_TB0(debug_pre_eret);
+ if (env->CP0_Status & (1 << CP0St_ERL)) {
env->PC = env->CP0_ErrorEPC;
- env->hflags &= ~MIPS_HFLAG_ERL;
- env->CP0_Status &= ~(1 << CP0St_ERL);
+ env->CP0_Status &= ~(1 << CP0St_ERL);
} else {
env->PC = env->CP0_EPC;
- env->hflags &= ~MIPS_HFLAG_EXL;
- env->CP0_Status &= ~(1 << CP0St_EXL);
+ env->CP0_Status &= ~(1 << CP0St_EXL);
}
+ if (!(env->CP0_Status & (1 << CP0St_EXL)) &&
+ !(env->CP0_Status & (1 << CP0St_ERL)) &&
+ !(env->hflags & MIPS_HFLAG_DM) &&
+ (env->CP0_Status & (1 << CP0St_UM)))
+ env->hflags |= MIPS_HFLAG_UM;
+ if (loglevel & CPU_LOG_EXEC)
+ CALL_FROM_TB0(debug_post_eret);
env->CP0_LLAddr = 1;
RETURN();
}
void op_deret (void)
{
- CALL_FROM_TB0(debug_eret);
+ if (loglevel & CPU_LOG_EXEC)
+ CALL_FROM_TB0(debug_pre_eret);
env->PC = env->CP0_DEPC;
+ env->hflags |= MIPS_HFLAG_DM;
+ if (!(env->CP0_Status & (1 << CP0St_EXL)) &&
+ !(env->CP0_Status & (1 << CP0St_ERL)) &&
+ !(env->hflags & MIPS_HFLAG_DM) &&
+ (env->CP0_Status & (1 << CP0St_UM)))
+ env->hflags |= MIPS_HFLAG_UM;
+ if (loglevel & CPU_LOG_EXEC)
+ CALL_FROM_TB0(debug_post_eret);
+ env->CP0_LLAddr = 1;
RETURN();
}
void op_rdhwr_cpunum(void)
{
- if (env->CP0_HWREna & (1 << 0))
- T0 = env->CP0_EBase & 0x2ff;
+ if (!(env->hflags & MIPS_HFLAG_UM) ||
+ (env->CP0_HWREna & (1 << 0)) ||
+ (env->CP0_Status & (1 << CP0St_CU0)))
+ T0 = env->CP0_EBase & 0x3ff;
else
- CALL_FROM_TB1(do_raise_exception_direct, EXCP_RI);
+ CALL_FROM_TB1(do_raise_exception, EXCP_RI);
RETURN();
}
void op_rdhwr_synci_step(void)
{
- if (env->CP0_HWREna & (1 << 1))
- T0 = env->SYNCI_Step;
+ if (!(env->hflags & MIPS_HFLAG_UM) ||
+ (env->CP0_HWREna & (1 << 1)) ||
+ (env->CP0_Status & (1 << CP0St_CU0)))
+ T0 = env->SYNCI_Step;
else
- CALL_FROM_TB1(do_raise_exception_direct, EXCP_RI);
+ CALL_FROM_TB1(do_raise_exception, EXCP_RI);
RETURN();
}
void op_rdhwr_cc(void)
{
- if (env->CP0_HWREna & (1 << 2))
- T0 = env->CP0_Count;
+ if (!(env->hflags & MIPS_HFLAG_UM) ||
+ (env->CP0_HWREna & (1 << 2)) ||
+ (env->CP0_Status & (1 << CP0St_CU0)))
+ T0 = env->CP0_Count;
else
- CALL_FROM_TB1(do_raise_exception_direct, EXCP_RI);
+ CALL_FROM_TB1(do_raise_exception, EXCP_RI);
RETURN();
}
void op_rdhwr_ccres(void)
{
- if (env->CP0_HWREna & (1 << 3))
- T0 = env->CCRes;
+ if (!(env->hflags & MIPS_HFLAG_UM) ||
+ (env->CP0_HWREna & (1 << 3)) ||
+ (env->CP0_Status & (1 << CP0St_CU0)))
+ T0 = env->CCRes;
else
- CALL_FROM_TB1(do_raise_exception_direct, EXCP_RI);
+ CALL_FROM_TB1(do_raise_exception, EXCP_RI);
RETURN();
}
@@ -2053,6 +2701,30 @@
RETURN();
}
+void op_save_fp_status (void)
+{
+ union fps {
+ uint32_t i;
+ float_status f;
+ } fps;
+ fps.i = PARAM1;
+ env->fp_status = fps.f;
+ RETURN();
+}
+
+void op_interrupt_restart (void)
+{
+ if (!(env->CP0_Status & (1 << CP0St_EXL)) &&
+ !(env->CP0_Status & (1 << CP0St_ERL)) &&
+ !(env->hflags & MIPS_HFLAG_DM) &&
+ (env->CP0_Status & (1 << CP0St_IE)) &&
+ (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask)) {
+ env->CP0_Cause &= ~(0x1f << CP0Ca_EC);
+ CALL_FROM_TB1(do_raise_exception, EXCP_EXT_INTERRUPT);
+ }
+ RETURN();
+}
+
void op_raise_exception (void)
{
CALL_FROM_TB1(do_raise_exception, PARAM1);
@@ -2084,7 +2756,7 @@
unsigned int pos = PARAM1;
unsigned int size = PARAM2;
- T0 = ((uint32_t)T1 >> pos) & ((1 << size) - 1);
+ T0 = ((uint32_t)T1 >> pos) & ((size < 32) ? ((1 << size) - 1) : ~0);
RETURN();
}
@@ -2092,9 +2764,9 @@
{
unsigned int pos = PARAM1;
unsigned int size = PARAM2;
- target_ulong mask = ((1 << size) - 1) << pos;
+ target_ulong mask = ((size < 32) ? ((1 << size) - 1) : ~0) << pos;
- T0 = (T2 & ~mask) | (((uint32_t)T1 << pos) & mask);
+ T0 = (T0 & ~mask) | (((uint32_t)T1 << pos) & mask);
RETURN();
}
@@ -2104,13 +2776,13 @@
RETURN();
}
-#ifdef MIPS_HAS_MIPS64
+#ifdef TARGET_MIPS64
void op_dext(void)
{
unsigned int pos = PARAM1;
unsigned int size = PARAM2;
- T0 = (T1 >> pos) & ((1 << size) - 1);
+ T0 = (T1 >> pos) & ((size < 32) ? ((1 << size) - 1) : ~0);
RETURN();
}
@@ -2118,9 +2790,9 @@
{
unsigned int pos = PARAM1;
unsigned int size = PARAM2;
- target_ulong mask = ((1 << size) - 1) << pos;
+ target_ulong mask = ((size < 32) ? ((1 << size) - 1) : ~0) << pos;
- T0 = (T2 & ~mask) | ((T1 << pos) & mask);
+ T0 = (T0 & ~mask) | ((T1 << pos) & mask);
RETURN();
}
Modified: trunk/src/host/qemu-neo1973/target-mips/op_helper.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-mips/op_helper.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/target-mips/op_helper.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -17,10 +17,9 @@
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
+#include <stdlib.h>
#include "exec.h"
-#define MIPS_DEBUG_DISAS
-
#define GETPC() (__builtin_return_address(0))
/*****************************************************************************/
@@ -56,12 +55,17 @@
cpu_restore_state (tb, env, pc, NULL);
}
-void do_raise_exception_direct (uint32_t exception)
+void do_raise_exception_direct_err (uint32_t exception, int error_code)
{
do_restore_state (GETPC ());
- do_raise_exception_err (exception, 0);
+ do_raise_exception_err (exception, error_code);
}
+void do_raise_exception_direct (uint32_t exception)
+{
+ do_raise_exception_direct_err (exception, 0);
+}
+
#define MEMSUFFIX _raw
#include "op_helper_mem.c"
#undef MEMSUFFIX
@@ -74,7 +78,7 @@
#undef MEMSUFFIX
#endif
-#ifdef MIPS_HAS_MIPS64
+#ifdef TARGET_MIPS64
#if TARGET_LONG_BITS > HOST_LONG_BITS
/* Those might call libgcc functions. */
void do_dsll (void)
@@ -114,8 +118,7 @@
if (T1) {
tmp = T0 << (0x40 - T1);
T0 = (T0 >> T1) | tmp;
- } else
- T0 = T1;
+ }
}
void do_drotr32 (void)
@@ -125,8 +128,7 @@
if (T1) {
tmp = T0 << (0x40 - (32 + T1));
T0 = (T0 >> (32 + T1)) | tmp;
- } else
- T0 = T1;
+ }
}
void do_dsllv (void)
@@ -156,7 +158,7 @@
T0 = T1;
}
#endif /* TARGET_LONG_BITS > HOST_LONG_BITS */
-#endif /* MIPS_HAS_MIPS64 */
+#endif /* TARGET_MIPS64 */
/* 64 bits arithmetic for 32 bits hosts */
#if TARGET_LONG_BITS > HOST_LONG_BITS
@@ -214,32 +216,48 @@
}
#endif
-#ifdef MIPS_HAS_MIPS64
+#if HOST_LONG_BITS < 64
+void do_div (void)
+{
+ /* 64bit datatypes because we may see overflow/underflow. */
+ if (T1 != 0) {
+ env->LO = (int32_t)((int64_t)(int32_t)T0 / (int32_t)T1);
+ env->HI = (int32_t)((int64_t)(int32_t)T0 % (int32_t)T1);
+ }
+}
+#endif
+
+#ifdef TARGET_MIPS64
void do_dmult (void)
{
+ env->LO = (int64_t)T0 * (int64_t)T1;
/* XXX */
- set_HILO((int64_t)T0 * (int64_t)T1);
+ env->HI = (env->LO | (1ULL << 63)) ? ~0ULL : 0ULL;
}
void do_dmultu (void)
{
+ env->LO = T0 * T1;
/* XXX */
- set_HILO((uint64_t)T0 * (uint64_t)T1);
+ env->HI = 0;
}
void do_ddiv (void)
{
if (T1 != 0) {
- env->LO = (int64_t)T0 / (int64_t)T1;
- env->HI = (int64_t)T0 % (int64_t)T1;
+ lldiv_t res = lldiv((int64_t)T0, (int64_t)T1);
+ env->LO = res.quot;
+ env->HI = res.rem;
}
}
void do_ddivu (void)
{
if (T1 != 0) {
- env->LO = T0 / T1;
- env->HI = T0 % T1;
+ /* XXX: lldivu? */
+ lldiv_t res = lldiv(T0, T1);
+ env->LO = (uint64_t)res.quot;
+ env->HI = (uint64_t)res.rem;
}
}
#endif
@@ -265,6 +283,11 @@
cpu_abort(env, "mtc0 compare\n");
}
+void cpu_mips_update_irq(CPUState *env)
+{
+ cpu_abort(env, "mtc0 status / mtc0 cause\n");
+}
+
void do_mtc0_status_debug(uint32_t old, uint32_t val)
{
cpu_abort(env, "mtc0 status debug\n");
@@ -315,10 +338,12 @@
void do_mtc0_status_debug(uint32_t old, uint32_t val)
{
- const uint32_t mask = 0x0000FF00;
- fprintf(logfile, "Status %08x => %08x Cause %08x (%08x %08x %08x)\n",
- old, val, env->CP0_Cause, old & mask, val & mask,
- env->CP0_Cause & mask);
+ fprintf(logfile, "Status %08x (%08x) => %08x (%08x) Cause %08x",
+ old, old & env->CP0_Cause & CP0Ca_IP_mask,
+ val, val & env->CP0_Cause & CP0Ca_IP_mask,
+ env->CP0_Cause);
+ (env->hflags & MIPS_HFLAG_UM) ? fputs(", UM\n", logfile)
+ : fputs("\n", logfile);
}
void do_mtc0_status_irqraise_debug(void)
@@ -326,9 +351,6 @@
fprintf(logfile, "Raise pending IRQs\n");
}
-#ifdef MIPS_USES_FPU
-#include "softfloat.h"
-
void fpu_handle_exception(void)
{
#ifdef CONFIG_SOFTFLOAT
@@ -365,7 +387,6 @@
SET_FP_CAUSE(env->fcr31, 0);
#endif
}
-#endif /* MIPS_USES_FPU */
/* TLB management */
#if defined(MIPS_USES_R4K_TLB)
@@ -373,7 +394,7 @@
{
/* Flush qemu's TLB and discard all shadowed entries. */
tlb_flush (env, flush_global);
- env->tlb_in_use = MIPS_TLB_NB;
+ env->tlb_in_use = env->nb_tlb;
}
static void mips_tlb_flush_extra (CPUState *env, int first)
@@ -387,16 +408,12 @@
static void fill_tlb (int idx)
{
tlb_t *tlb;
- int size;
/* XXX: detect conflicting TLBs and raise a MCHECK exception when needed */
tlb = &env->tlb[idx];
- tlb->VPN = env->CP0_EntryHi & (int32_t)0xFFFFE000;
+ tlb->VPN = env->CP0_EntryHi & ~(target_ulong)0x1FFF;
tlb->ASID = env->CP0_EntryHi & 0xFF;
- size = env->CP0_PageMask >> 13;
- size = 4 * (size + 1);
- tlb->end = tlb->VPN + (1 << (8 + size));
- tlb->end2 = tlb->end + (1 << (8 + size));
+ tlb->PageMask = env->CP0_PageMask;
tlb->G = env->CP0_EntryLo0 & env->CP0_EntryLo1 & 1;
tlb->V0 = (env->CP0_EntryLo0 & 2) != 0;
tlb->D0 = (env->CP0_EntryLo0 & 4) != 0;
@@ -413,12 +430,10 @@
/* Discard cached TLB entries. We could avoid doing this if the
tlbwi is just upgrading access permissions on the current entry;
that might be a further win. */
- mips_tlb_flush_extra (env, MIPS_TLB_NB);
+ mips_tlb_flush_extra (env, env->nb_tlb);
- /* Wildly undefined effects for CP0_index containing a too high value and
- MIPS_TLB_NB not being a power of two. But so does real silicon. */
- invalidate_tlb(env, env->CP0_index & (MIPS_TLB_NB - 1), 0);
- fill_tlb(env->CP0_index & (MIPS_TLB_NB - 1));
+ invalidate_tlb(env, env->CP0_Index % env->nb_tlb, 0);
+ fill_tlb(env->CP0_Index % env->nb_tlb);
}
void do_tlbwr (void)
@@ -438,18 +453,18 @@
tag = env->CP0_EntryHi & (int32_t)0xFFFFE000;
ASID = env->CP0_EntryHi & 0xFF;
- for (i = 0; i < MIPS_TLB_NB; i++) {
+ for (i = 0; i < env->nb_tlb; i++) {
tlb = &env->tlb[i];
/* Check ASID, virtual page number & size */
if ((tlb->G == 1 || tlb->ASID == ASID) && tlb->VPN == tag) {
/* TLB match */
- env->CP0_index = i;
+ env->CP0_Index = i;
break;
}
}
- if (i == MIPS_TLB_NB) {
+ if (i == env->nb_tlb) {
/* No match. Discard any shadow entries, if any of them match. */
- for (i = MIPS_TLB_NB; i < env->tlb_in_use; i++) {
+ for (i = env->nb_tlb; i < env->tlb_in_use; i++) {
tlb = &env->tlb[i];
/* Check ASID, virtual page number & size */
@@ -459,7 +474,7 @@
}
}
- env->CP0_index |= 0x80000000;
+ env->CP0_Index |= 0x80000000;
}
}
@@ -467,20 +482,18 @@
{
tlb_t *tlb;
uint8_t ASID;
- int size;
ASID = env->CP0_EntryHi & 0xFF;
- tlb = &env->tlb[env->CP0_index & (MIPS_TLB_NB - 1)];
+ tlb = &env->tlb[env->CP0_Index % env->nb_tlb];
/* If this will change the current ASID, flush qemu's TLB. */
if (ASID != tlb->ASID)
cpu_mips_tlb_flush (env, 1);
- mips_tlb_flush_extra(env, MIPS_TLB_NB);
+ mips_tlb_flush_extra(env, env->nb_tlb);
env->CP0_EntryHi = tlb->VPN | tlb->ASID;
- size = (tlb->end - tlb->VPN) >> 12;
- env->CP0_PageMask = (size - 1) << 13;
+ env->CP0_PageMask = tlb->PageMask;
env->CP0_EntryLo0 = tlb->G | (tlb->V0 << 1) | (tlb->D0 << 2) |
(tlb->C0 << 3) | (tlb->PFN[0] >> 6);
env->CP0_EntryLo1 = tlb->G | (tlb->V1 << 1) | (tlb->D1 << 2) |
@@ -493,26 +506,42 @@
void dump_ldst (const unsigned char *func)
{
if (loglevel)
- fprintf(logfile, "%s => " TLSZ " " TLSZ "\n", __func__, T0, T1);
+ fprintf(logfile, "%s => " TARGET_FMT_lx " " TARGET_FMT_lx "\n", __func__, T0, T1);
}
void dump_sc (void)
{
if (loglevel) {
- fprintf(logfile, "%s " TLSZ " at " TLSZ " (" TLSZ ")\n", __func__,
+ fprintf(logfile, "%s " TARGET_FMT_lx " at " TARGET_FMT_lx " (" TARGET_FMT_lx ")\n", __func__,
T1, T0, env->CP0_LLAddr);
}
}
-void debug_eret (void)
+void debug_pre_eret (void)
{
- if (loglevel) {
- fprintf(logfile, "ERET: pc " TLSZ " EPC " TLSZ " ErrorEPC " TLSZ " (%d)\n",
- env->PC, env->CP0_EPC, env->CP0_ErrorEPC,
- env->hflags & MIPS_HFLAG_ERL ? 1 : 0);
- }
+ fprintf(logfile, "ERET: PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
+ env->PC, env->CP0_EPC);
+ if (env->CP0_Status & (1 << CP0St_ERL))
+ fprintf(logfile, " ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
+ if (env->hflags & MIPS_HFLAG_DM)
+ fprintf(logfile, " DEPC " TARGET_FMT_lx, env->CP0_DEPC);
+ fputs("\n", logfile);
}
+void debug_post_eret (void)
+{
+ fprintf(logfile, " => PC " TARGET_FMT_lx " EPC " TARGET_FMT_lx,
+ env->PC, env->CP0_EPC);
+ if (env->CP0_Status & (1 << CP0St_ERL))
+ fprintf(logfile, " ErrorEPC " TARGET_FMT_lx, env->CP0_ErrorEPC);
+ if (env->hflags & MIPS_HFLAG_DM)
+ fprintf(logfile, " DEPC " TARGET_FMT_lx, env->CP0_DEPC);
+ if (env->hflags & MIPS_HFLAG_UM)
+ fputs(", UM\n", logfile);
+ else
+ fputs("\n", logfile);
+}
+
void do_pmon (int function)
{
function /= 2;
Modified: trunk/src/host/qemu-neo1973/target-mips/op_helper_mem.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-mips/op_helper_mem.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/target-mips/op_helper_mem.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -28,7 +28,7 @@
}
#if defined (DEBUG_OP)
if (logfile) {
- fprintf(logfile, "%s: " TLSZ " - %08x " TLSZ " => " TLSZ "\n",
+ fprintf(logfile, "%s: " TARGET_FMT_lx " - %08x " TARGET_FMT_lx " => " TARGET_FMT_lx "\n",
__func__, sav, tmp, T1, T0);
}
#endif
@@ -57,7 +57,7 @@
}
#if defined (DEBUG_OP)
if (logfile) {
- fprintf(logfile, "%s: " TLSZ " - %08x " TLSZ " => " TLSZ "\n",
+ fprintf(logfile, "%s: " TARGET_FMT_lx " - %08x " TARGET_FMT_lx " => " TARGET_FMT_lx "\n",
__func__, sav, tmp, T1, T0);
}
#endif
@@ -86,7 +86,7 @@
}
#if defined (DEBUG_OP)
if (logfile) {
- fprintf(logfile, "%s: " TLSZ " - " TLSZ " " TLSZ " => %08x\n",
+ fprintf(logfile, "%s: " TARGET_FMT_lx " - " TARGET_FMT_lx " " TARGET_FMT_lx " => %08x\n",
__func__, T0, sav, T1, tmp);
}
#endif
@@ -116,7 +116,7 @@
}
#if defined (DEBUG_OP)
if (logfile) {
- fprintf(logfile, "%s: " TLSZ " - " TLSZ " " TLSZ " => %08x\n",
+ fprintf(logfile, "%s: " TARGET_FMT_lx " - " TARGET_FMT_lx " " TARGET_FMT_lx " => %08x\n",
__func__, T0, sav, T1, tmp);
}
#endif
@@ -124,12 +124,12 @@
return tmp;
}
-#ifdef MIPS_HAS_MIPS64
+#ifdef TARGET_MIPS64
-# ifdef TARGET_WORDS_BIGENDIAN
-#define GET_LMASK64(v) ((v) & 4)
+#ifdef TARGET_WORDS_BIGENDIAN
+#define GET_LMASK64(v) ((v) & 7)
#else
-#define GET_LMASK64(v) (((v) & 4) ^ 4)
+#define GET_LMASK64(v) (((v) & 7) ^ 7)
#endif
void glue(do_ldl, MEMSUFFIX) (uint64_t tmp)
@@ -166,7 +166,7 @@
}
#if defined (DEBUG_OP)
if (logfile) {
- fprintf(logfile, "%s: " TLSZ " - " TLSZ " " TLSZ " => " TLSZ "\n",
+ fprintf(logfile, "%s: " TARGET_FMT_lx " - " TARGET_FMT_lx " " TARGET_FMT_lx " => " TARGET_FMT_lx "\n",
__func__, sav, tmp, T1, T0);
}
#endif
@@ -207,7 +207,7 @@
}
#if defined (DEBUG_OP)
if (logfile) {
- fprintf(logfile, "%s: " TLSZ " - " TLSZ " " TLSZ " => " TLSZ "\n",
+ fprintf(logfile, "%s: " TARGET_FMT_lx " - " TARGET_FMT_lx " " TARGET_FMT_lx " => " TARGET_FMT_lx "\n",
__func__, sav, tmp, T1, T0);
}
#endif
@@ -248,7 +248,7 @@
}
#if defined (DEBUG_OP)
if (logfile) {
- fprintf(logfile, "%s: " TLSZ " - " TLSZ " " TLSZ " => " TLSZ "\n",
+ fprintf(logfile, "%s: " TARGET_FMT_lx " - " TARGET_FMT_lx " " TARGET_FMT_lx " => " TARGET_FMT_lx "\n",
__func__, T0, sav, T1, tmp);
}
#endif
@@ -290,7 +290,7 @@
}
#if defined (DEBUG_OP)
if (logfile) {
- fprintf(logfile, "%s: " TLSZ " - " TLSZ " " TLSZ " => " TLSZ "\n",
+ fprintf(logfile, "%s: " TARGET_FMT_lx " - " TARGET_FMT_lx " " TARGET_FMT_lx " => " TARGET_FMT_lx "\n",
__func__, T0, sav, T1, tmp);
}
#endif
@@ -298,4 +298,4 @@
return tmp;
}
-#endif /* MIPS_HAS_MIPS64 */
+#endif /* TARGET_MIPS64 */
Modified: trunk/src/host/qemu-neo1973/target-mips/op_mem.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-mips/op_mem.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/target-mips/op_mem.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -117,6 +117,10 @@
void glue(op_sc, MEMSUFFIX) (void)
{
CALL_FROM_TB0(dump_sc);
+ if (T0 & 0x3) {
+ env->CP0_BadVAddr = T0;
+ CALL_FROM_TB1(do_raise_exception, EXCP_AdES);
+ }
if (T0 == env->CP0_LLAddr) {
glue(stl, MEMSUFFIX)(T0, T1);
T0 = 1;
@@ -126,7 +130,7 @@
RETURN();
}
-#ifdef MIPS_HAS_MIPS64
+#ifdef TARGET_MIPS64
void glue(op_ld, MEMSUFFIX) (void)
{
T0 = glue(ldq, MEMSUFFIX)(T0);
@@ -182,6 +186,10 @@
void glue(op_scd, MEMSUFFIX) (void)
{
CALL_FROM_TB0(dump_sc);
+ if (T0 & 0x7) {
+ env->CP0_BadVAddr = T0;
+ CALL_FROM_TB1(do_raise_exception, EXCP_AdES);
+ }
if (T0 == env->CP0_LLAddr) {
glue(stq, MEMSUFFIX)(T0, T1);
T0 = 1;
@@ -190,9 +198,8 @@
}
RETURN();
}
-#endif /* MIPS_HAS_MIPS64 */
+#endif /* TARGET_MIPS64 */
-#ifdef MIPS_USES_FPU
void glue(op_lwc1, MEMSUFFIX) (void)
{
WT0 = glue(ldl, MEMSUFFIX)(T0);
@@ -213,4 +220,35 @@
glue(stq, MEMSUFFIX)(T0, DT0);
RETURN();
}
-#endif
+void glue(op_lwxc1, MEMSUFFIX) (void)
+{
+ WT0 = glue(ldl, MEMSUFFIX)(T0 + T1);
+ RETURN();
+}
+void glue(op_swxc1, MEMSUFFIX) (void)
+{
+ glue(stl, MEMSUFFIX)(T0 + T1, WT0);
+ RETURN();
+}
+void glue(op_ldxc1, MEMSUFFIX) (void)
+{
+ DT0 = glue(ldq, MEMSUFFIX)(T0 + T1);
+ RETURN();
+}
+void glue(op_sdxc1, MEMSUFFIX) (void)
+{
+ glue(stq, MEMSUFFIX)(T0 + T1, DT0);
+ RETURN();
+}
+void glue(op_luxc1, MEMSUFFIX) (void)
+{
+ /* XXX: is defined as unaligned */
+ DT0 = glue(ldq, MEMSUFFIX)(T0 + T1);
+ RETURN();
+}
+void glue(op_suxc1, MEMSUFFIX) (void)
+{
+ /* XXX: is defined as unaligned */
+ glue(stq, MEMSUFFIX)(T0 + T1, DT0);
+ RETURN();
+}
Modified: trunk/src/host/qemu-neo1973/target-mips/op_template.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-mips/op_template.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/target-mips/op_template.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -54,7 +54,7 @@
#define SET_RESET(treg, tregname) \
void glue(op_set, tregname)(void) \
{ \
- treg = PARAM1; \
+ treg = (int32_t)PARAM1; \
RETURN(); \
} \
void glue(op_reset, tregname)(void) \
Modified: trunk/src/host/qemu-neo1973/target-mips/translate.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-mips/translate.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/target-mips/translate.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -305,7 +305,7 @@
};
/* MFMC0 opcodes */
-#define MASK_MFMC0(op) MASK_CP0(op) | (op & ((0x0C << 11) | (1 << 5)))
+#define MASK_MFMC0(op) MASK_CP0(op) | (op & 0xFFFF)
enum {
OPC_DI = (0 << 5) | (0x0C << 11) | OPC_MFMC0,
@@ -333,20 +333,26 @@
OPC_MFC1 = (0x00 << 21) | OPC_CP1,
OPC_DMFC1 = (0x01 << 21) | OPC_CP1,
OPC_CFC1 = (0x02 << 21) | OPC_CP1,
- OPC_MFHCI = (0x03 << 21) | OPC_CP1,
+ OPC_MFHC1 = (0x03 << 21) | OPC_CP1,
OPC_MTC1 = (0x04 << 21) | OPC_CP1,
OPC_DMTC1 = (0x05 << 21) | OPC_CP1,
OPC_CTC1 = (0x06 << 21) | OPC_CP1,
- OPC_MTHCI = (0x07 << 21) | OPC_CP1,
+ OPC_MTHC1 = (0x07 << 21) | OPC_CP1,
OPC_BC1 = (0x08 << 21) | OPC_CP1, /* bc */
+ OPC_BC1ANY2 = (0x09 << 21) | OPC_CP1,
+ OPC_BC1ANY4 = (0x0A << 21) | OPC_CP1,
OPC_S_FMT = (0x10 << 21) | OPC_CP1, /* 16: fmt=single fp */
OPC_D_FMT = (0x11 << 21) | OPC_CP1, /* 17: fmt=double fp */
OPC_E_FMT = (0x12 << 21) | OPC_CP1, /* 18: fmt=extended fp */
OPC_Q_FMT = (0x13 << 21) | OPC_CP1, /* 19: fmt=quad fp */
OPC_W_FMT = (0x14 << 21) | OPC_CP1, /* 20: fmt=32bit fixed */
OPC_L_FMT = (0x15 << 21) | OPC_CP1, /* 21: fmt=64bit fixed */
+ OPC_PS_FMT = (0x16 << 21) | OPC_CP1, /* 22: fmt=paired single fp */
};
+#define MASK_CP1_FUNC(op) MASK_CP1(op) | (op & 0x3F)
+#define MASK_BC1(op) MASK_CP1(op) | (op & (0x3 << 16))
+
enum {
OPC_BC1F = (0x00 << 16) | OPC_BC1,
OPC_BC1T = (0x01 << 16) | OPC_BC1,
@@ -354,12 +360,56 @@
OPC_BC1TL = (0x03 << 16) | OPC_BC1,
};
-#define MASK_CP1_BCOND(op) MASK_CP1(op) | (op & (0x3 << 16))
-#define MASK_CP1_FUNC(op) MASK_CP1(op) | (op & 0x3F)
+enum {
+ OPC_BC1FANY2 = (0x00 << 16) | OPC_BC1ANY2,
+ OPC_BC1TANY2 = (0x01 << 16) | OPC_BC1ANY2,
+};
+enum {
+ OPC_BC1FANY4 = (0x00 << 16) | OPC_BC1ANY4,
+ OPC_BC1TANY4 = (0x01 << 16) | OPC_BC1ANY4,
+};
+
#define MASK_CP2(op) MASK_OP_MAJOR(op) | (op & (0x1F << 21))
-#define MASK_CP3(op) MASK_OP_MAJOR(op) | (op & (0x1F << 21))
+enum {
+ OPC_MFC2 = (0x00 << 21) | OPC_CP2,
+ OPC_DMFC2 = (0x01 << 21) | OPC_CP2,
+ OPC_CFC2 = (0x02 << 21) | OPC_CP2,
+ OPC_MFHC2 = (0x03 << 21) | OPC_CP2,
+ OPC_MTC2 = (0x04 << 21) | OPC_CP2,
+ OPC_DMTC2 = (0x05 << 21) | OPC_CP2,
+ OPC_CTC2 = (0x06 << 21) | OPC_CP2,
+ OPC_MTHC2 = (0x07 << 21) | OPC_CP2,
+ OPC_BC2 = (0x08 << 21) | OPC_CP2,
+};
+
+#define MASK_CP3(op) MASK_OP_MAJOR(op) | (op & 0x3F)
+
+enum {
+ OPC_LWXC1 = 0x00 | OPC_CP3,
+ OPC_LDXC1 = 0x01 | OPC_CP3,
+ OPC_LUXC1 = 0x05 | OPC_CP3,
+ OPC_SWXC1 = 0x08 | OPC_CP3,
+ OPC_SDXC1 = 0x09 | OPC_CP3,
+ OPC_SUXC1 = 0x0D | OPC_CP3,
+ OPC_PREFX = 0x0F | OPC_CP3,
+ OPC_ALNV_PS = 0x1E | OPC_CP3,
+ OPC_MADD_S = 0x20 | OPC_CP3,
+ OPC_MADD_D = 0x21 | OPC_CP3,
+ OPC_MADD_PS = 0x26 | OPC_CP3,
+ OPC_MSUB_S = 0x28 | OPC_CP3,
+ OPC_MSUB_D = 0x29 | OPC_CP3,
+ OPC_MSUB_PS = 0x2E | OPC_CP3,
+ OPC_NMADD_S = 0x30 | OPC_CP3,
+ OPC_NMADD_D = 0x32 | OPC_CP3,
+ OPC_NMADD_PS= 0x36 | OPC_CP3,
+ OPC_NMSUB_S = 0x38 | OPC_CP3,
+ OPC_NMSUB_D = 0x39 | OPC_CP3,
+ OPC_NMSUB_PS= 0x3E | OPC_CP3,
+};
+
+
const unsigned char *regnames[] =
{ "r0", "at", "v0", "v1", "a0", "a1", "a2", "a3",
"t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
@@ -367,20 +417,20 @@
"t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra", };
/* Warning: no function for r0 register (hard wired to zero) */
-#define GEN32(func, NAME) \
-static GenOpFunc *NAME ## _table [32] = { \
-NULL, NAME ## 1, NAME ## 2, NAME ## 3, \
-NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \
-NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \
-NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15, \
-NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19, \
-NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23, \
-NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27, \
-NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31, \
-}; \
-static inline void func(int n) \
-{ \
- NAME ## _table[n](); \
+#define GEN32(func, NAME) \
+static GenOpFunc *NAME ## _table [32] = { \
+NULL, NAME ## 1, NAME ## 2, NAME ## 3, \
+NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \
+NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \
+NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15, \
+NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19, \
+NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23, \
+NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27, \
+NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31, \
+}; \
+static inline void func(int n) \
+{ \
+ NAME ## _table[n](); \
}
/* General purpose registers moves */
@@ -391,66 +441,57 @@
GEN32(gen_op_store_T0_gpr, gen_op_store_T0_gpr_gpr);
GEN32(gen_op_store_T1_gpr, gen_op_store_T1_gpr_gpr);
-#ifdef MIPS_USES_FPU
-
static const char *fregnames[] =
{ "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", };
-# define SFGEN32(func, NAME) \
-static GenOpFunc *NAME ## _table [32] = { \
-NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3, \
-NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \
-NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \
-NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15, \
-NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19, \
-NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23, \
-NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27, \
-NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31, \
-}; \
-static inline void func(int n) \
-{ \
- NAME ## _table[n](); \
+#define FGEN32(func, NAME) \
+static GenOpFunc *NAME ## _table [32] = { \
+NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3, \
+NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \
+NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \
+NAME ## 12, NAME ## 13, NAME ## 14, NAME ## 15, \
+NAME ## 16, NAME ## 17, NAME ## 18, NAME ## 19, \
+NAME ## 20, NAME ## 21, NAME ## 22, NAME ## 23, \
+NAME ## 24, NAME ## 25, NAME ## 26, NAME ## 27, \
+NAME ## 28, NAME ## 29, NAME ## 30, NAME ## 31, \
+}; \
+static inline void func(int n) \
+{ \
+ NAME ## _table[n](); \
}
-# define DFGEN32(func, NAME) \
-static GenOpFunc *NAME ## _table [32] = { \
-NAME ## 0, 0, NAME ## 2, 0, \
-NAME ## 4, 0, NAME ## 6, 0, \
-NAME ## 8, 0, NAME ## 10, 0, \
-NAME ## 12, 0, NAME ## 14, 0, \
-NAME ## 16, 0, NAME ## 18, 0, \
-NAME ## 20, 0, NAME ## 22, 0, \
-NAME ## 24, 0, NAME ## 26, 0, \
-NAME ## 28, 0, NAME ## 30, 0, \
-}; \
-static inline void func(int n) \
-{ \
- NAME ## _table[n](); \
-}
+FGEN32(gen_op_load_fpr_WT0, gen_op_load_fpr_WT0_fpr);
+FGEN32(gen_op_store_fpr_WT0, gen_op_store_fpr_WT0_fpr);
-SFGEN32(gen_op_load_fpr_WT0, gen_op_load_fpr_WT0_fpr);
-SFGEN32(gen_op_store_fpr_WT0, gen_op_store_fpr_WT0_fpr);
+FGEN32(gen_op_load_fpr_WT1, gen_op_load_fpr_WT1_fpr);
+FGEN32(gen_op_store_fpr_WT1, gen_op_store_fpr_WT1_fpr);
-SFGEN32(gen_op_load_fpr_WT1, gen_op_load_fpr_WT1_fpr);
-SFGEN32(gen_op_store_fpr_WT1, gen_op_store_fpr_WT1_fpr);
+FGEN32(gen_op_load_fpr_WT2, gen_op_load_fpr_WT2_fpr);
+FGEN32(gen_op_store_fpr_WT2, gen_op_store_fpr_WT2_fpr);
-SFGEN32(gen_op_load_fpr_WT2, gen_op_load_fpr_WT2_fpr);
-SFGEN32(gen_op_store_fpr_WT2, gen_op_store_fpr_WT2_fpr);
+FGEN32(gen_op_load_fpr_DT0, gen_op_load_fpr_DT0_fpr);
+FGEN32(gen_op_store_fpr_DT0, gen_op_store_fpr_DT0_fpr);
-DFGEN32(gen_op_load_fpr_DT0, gen_op_load_fpr_DT0_fpr);
-DFGEN32(gen_op_store_fpr_DT0, gen_op_store_fpr_DT0_fpr);
+FGEN32(gen_op_load_fpr_DT1, gen_op_load_fpr_DT1_fpr);
+FGEN32(gen_op_store_fpr_DT1, gen_op_store_fpr_DT1_fpr);
-DFGEN32(gen_op_load_fpr_DT1, gen_op_load_fpr_DT1_fpr);
-DFGEN32(gen_op_store_fpr_DT1, gen_op_store_fpr_DT1_fpr);
+FGEN32(gen_op_load_fpr_DT2, gen_op_load_fpr_DT2_fpr);
+FGEN32(gen_op_store_fpr_DT2, gen_op_store_fpr_DT2_fpr);
-DFGEN32(gen_op_load_fpr_DT2, gen_op_load_fpr_DT2_fpr);
-DFGEN32(gen_op_store_fpr_DT2, gen_op_store_fpr_DT2_fpr);
+FGEN32(gen_op_load_fpr_WTH0, gen_op_load_fpr_WTH0_fpr);
+FGEN32(gen_op_store_fpr_WTH0, gen_op_store_fpr_WTH0_fpr);
+FGEN32(gen_op_load_fpr_WTH1, gen_op_load_fpr_WTH1_fpr);
+FGEN32(gen_op_store_fpr_WTH1, gen_op_store_fpr_WTH1_fpr);
+
+FGEN32(gen_op_load_fpr_WTH2, gen_op_load_fpr_WTH2_fpr);
+FGEN32(gen_op_store_fpr_WTH2, gen_op_store_fpr_WTH2_fpr);
+
#define FOP_CONDS(fmt) \
-static GenOpFunc * cond_ ## fmt ## _table[16] = { \
+static GenOpFunc1 * cond_ ## fmt ## _table[16] = { \
gen_op_cmp_ ## fmt ## _f, \
gen_op_cmp_ ## fmt ## _un, \
gen_op_cmp_ ## fmt ## _eq, \
@@ -468,20 +509,20 @@
gen_op_cmp_ ## fmt ## _le, \
gen_op_cmp_ ## fmt ## _ngt, \
}; \
-static inline void gen_cmp_ ## fmt(int n) \
+static inline void gen_cmp_ ## fmt(int n, long cc) \
{ \
- cond_ ## fmt ## _table[n](); \
+ cond_ ## fmt ## _table[n](cc); \
}
FOP_CONDS(d)
FOP_CONDS(s)
+FOP_CONDS(ps)
-#endif /* MIPS_USES_FPU */
-
typedef struct DisasContext {
struct TranslationBlock *tb;
target_ulong pc, saved_pc;
uint32_t opcode;
+ uint32_t fp_status, saved_fp_status;
/* Routine used to access memory */
int mem_idx;
uint32_t hflags, saved_hflags;
@@ -503,7 +544,7 @@
#define MIPS_DEBUG(fmt, args...) \
do { \
if (loglevel & CPU_LOG_TB_IN_ASM) { \
- fprintf(logfile, TLSZ ": %08x " fmt "\n", \
+ fprintf(logfile, TARGET_FMT_lx ": %08x " fmt "\n", \
ctx->pc, ctx->opcode , ##args); \
} \
} while (0)
@@ -567,17 +608,31 @@
if (ctx->hflags != ctx->saved_hflags) {
gen_op_save_state(ctx->hflags);
ctx->saved_hflags = ctx->hflags;
- if (ctx->hflags & MIPS_HFLAG_BR) {
+ switch (ctx->hflags & MIPS_HFLAG_BMASK) {
+ case MIPS_HFLAG_BR:
gen_op_save_breg_target();
- } else if (ctx->hflags & MIPS_HFLAG_B) {
- gen_op_save_btarget(ctx->btarget);
- } else if (ctx->hflags & MIPS_HFLAG_BMASK) {
+ break;
+ case MIPS_HFLAG_BC:
gen_op_save_bcond();
+ /* fall through */
+ case MIPS_HFLAG_BL:
+ /* bcond was already saved by the BL insn */
+ /* fall through */
+ case MIPS_HFLAG_B:
gen_op_save_btarget(ctx->btarget);
+ break;
}
}
}
+static inline void save_fpu_state (DisasContext *ctx)
+{
+ if (ctx->fp_status != ctx->saved_fp_status) {
+ gen_op_save_fp_status(ctx->fp_status);
+ ctx->saved_fp_status = ctx->fp_status;
+ }
+}
+
static inline void generate_exception_err (DisasContext *ctx, int excp, int err)
{
#if defined MIPS_DEBUG_DISAS
@@ -615,7 +670,7 @@
}
#endif
-#ifdef MIPS_HAS_MIPS64
+#ifdef TARGET_MIPS64
OP_LD_TABLE(d);
OP_LD_TABLE(dl);
OP_LD_TABLE(dr);
@@ -640,12 +695,16 @@
OP_ST_TABLE(b);
OP_LD_TABLE(l);
OP_ST_TABLE(c);
-#ifdef MIPS_USES_FPU
OP_LD_TABLE(wc1);
OP_ST_TABLE(wc1);
OP_LD_TABLE(dc1);
OP_ST_TABLE(dc1);
-#endif
+OP_LD_TABLE(wxc1);
+OP_ST_TABLE(wxc1);
+OP_LD_TABLE(dxc1);
+OP_ST_TABLE(dxc1);
+OP_LD_TABLE(uxc1);
+OP_ST_TABLE(uxc1);
/* Load and store */
static void gen_ldst (DisasContext *ctx, uint32_t opc, int rt,
@@ -660,13 +719,13 @@
} else {
gen_op_load_gpr_T0(base);
gen_op_set_T1(offset);
- gen_op_add();
+ gen_op_addr_add();
}
/* Don't do NOP if destination is zero: we must perform the actual
* memory access
*/
switch (opc) {
-#ifdef MIPS_HAS_MIPS64
+#ifdef TARGET_MIPS64
case OPC_LD:
op_ldst(ld);
GEN_STORE_TN_REG(rt, T0);
@@ -683,6 +742,7 @@
opn = "sd";
break;
case OPC_SCD:
+ save_cpu_state(ctx, 1);
GEN_LOAD_REG_TN(T1, rt);
op_ldst(scd);
opn = "scd";
@@ -781,6 +841,7 @@
opn = "ll";
break;
case OPC_SC:
+ save_cpu_state(ctx, 1);
GEN_LOAD_REG_TN(T1, rt);
op_ldst(sc);
GEN_STORE_TN_REG(rt, T0);
@@ -794,8 +855,6 @@
MIPS_DEBUG("%s %s, %d(%s)", opn, regnames[rt], offset, regnames[base]);
}
-#ifdef MIPS_USES_FPU
-
/* Load and store */
static void gen_flt_ldst (DisasContext *ctx, uint32_t opc, int ft,
int base, int16_t offset)
@@ -809,7 +868,7 @@
} else {
gen_op_load_gpr_T0(base);
gen_op_set_T1(offset);
- gen_op_add();
+ gen_op_addr_add();
}
/* Don't do NOP if destination is zero: we must perform the actual
* memory access
@@ -837,14 +896,12 @@
break;
default:
MIPS_INVAL("float load/store");
- generate_exception_err(ctx, EXCP_CpU, 1);
+ generate_exception(ctx, EXCP_RI);
return;
}
MIPS_DEBUG("%s %s, %d(%s)", opn, fregnames[ft], offset, regnames[base]);
}
-#endif /* MIPS_USES_FPU */
-
/* Arithmetic with immediate operand */
static void gen_arith_imm (DisasContext *ctx, uint32_t opc, int rt,
int rs, int16_t imm)
@@ -859,18 +916,42 @@
MIPS_DEBUG("NOP");
return;
}
- if (opc == OPC_ADDI || opc == OPC_ADDIU ||
- opc == OPC_DADDI || opc == OPC_DADDIU ||
- opc == OPC_SLTI || opc == OPC_SLTIU)
+ uimm = (uint16_t)imm;
+ switch (opc) {
+ case OPC_ADDI:
+ case OPC_ADDIU:
+#ifdef TARGET_MIPS64
+ case OPC_DADDI:
+ case OPC_DADDIU:
+#endif
+ case OPC_SLTI:
+ case OPC_SLTIU:
uimm = (int32_t)imm; /* Sign extend to 32 bits */
- else
- uimm = (uint16_t)imm;
- if (opc != OPC_LUI) {
+ /* Fall through. */
+ case OPC_ANDI:
+ case OPC_ORI:
+ case OPC_XORI:
GEN_LOAD_REG_TN(T0, rs);
GEN_LOAD_IMM_TN(T1, uimm);
- } else {
- uimm = uimm << 16;
- GEN_LOAD_IMM_TN(T0, uimm);
+ break;
+ case OPC_LUI:
+ GEN_LOAD_IMM_TN(T0, uimm << 16);
+ break;
+ case OPC_SLL:
+ case OPC_SRA:
+ case OPC_SRL:
+#ifdef TARGET_MIPS64
+ case OPC_DSLL:
+ case OPC_DSRA:
+ case OPC_DSRL:
+ case OPC_DSLL32:
+ case OPC_DSRA32:
+ case OPC_DSRL32:
+#endif
+ uimm &= 0x1f;
+ GEN_LOAD_REG_TN(T0, rs);
+ GEN_LOAD_IMM_TN(T1, uimm);
+ break;
}
switch (opc) {
case OPC_ADDI:
@@ -882,7 +963,7 @@
gen_op_add();
opn = "addiu";
break;
-#ifdef MIPS_HAS_MIPS64
+#ifdef TARGET_MIPS64
case OPC_DADDI:
save_cpu_state(ctx, 1);
gen_op_daddo();
@@ -925,15 +1006,22 @@
opn = "sra";
break;
case OPC_SRL:
- if ((ctx->opcode >> 21) & 1) {
+ switch ((ctx->opcode >> 21) & 0x1f) {
+ case 0:
+ gen_op_srl();
+ opn = "srl";
+ break;
+ case 1:
gen_op_rotr();
opn = "rotr";
- } else {
- gen_op_srl();
- opn = "srl";
- }
+ break;
+ default:
+ MIPS_INVAL("invalid srl flag");
+ generate_exception(ctx, EXCP_RI);
+ break;
+ }
break;
-#ifdef MIPS_HAS_MIPS64
+#ifdef TARGET_MIPS64
case OPC_DSLL:
gen_op_dsll();
opn = "dsll";
@@ -943,13 +1031,20 @@
opn = "dsra";
break;
case OPC_DSRL:
- if ((ctx->opcode >> 21) & 1) {
+ switch ((ctx->opcode >> 21) & 0x1f) {
+ case 0:
+ gen_op_dsrl();
+ opn = "dsrl";
+ break;
+ case 1:
gen_op_drotr();
opn = "drotr";
- } else {
- gen_op_dsrl();
- opn = "dsrl";
- }
+ break;
+ default:
+ MIPS_INVAL("invalid dsrl flag");
+ generate_exception(ctx, EXCP_RI);
+ break;
+ }
break;
case OPC_DSLL32:
gen_op_dsll32();
@@ -960,13 +1055,20 @@
opn = "dsra32";
break;
case OPC_DSRL32:
- if ((ctx->opcode >> 21) & 1) {
+ switch ((ctx->opcode >> 21) & 0x1f) {
+ case 0:
+ gen_op_dsrl32();
+ opn = "dsrl32";
+ break;
+ case 1:
gen_op_drotr32();
opn = "drotr32";
- } else {
- gen_op_dsrl32();
- opn = "dsrl32";
- }
+ break;
+ default:
+ MIPS_INVAL("invalid dsrl32 flag");
+ generate_exception(ctx, EXCP_RI);
+ break;
+ }
break;
#endif
default:
@@ -1013,7 +1115,7 @@
gen_op_sub();
opn = "subu";
break;
-#ifdef MIPS_HAS_MIPS64
+#ifdef TARGET_MIPS64
case OPC_DADD:
save_cpu_state(ctx, 1);
gen_op_daddo();
@@ -1078,15 +1180,22 @@
opn = "srav";
break;
case OPC_SRLV:
- if ((ctx->opcode >> 6) & 1) {
+ switch ((ctx->opcode >> 6) & 0x1f) {
+ case 0:
+ gen_op_srlv();
+ opn = "srlv";
+ break;
+ case 1:
gen_op_rotrv();
opn = "rotrv";
- } else {
- gen_op_srlv();
- opn = "srlv";
- }
+ break;
+ default:
+ MIPS_INVAL("invalid srlv flag");
+ generate_exception(ctx, EXCP_RI);
+ break;
+ }
break;
-#ifdef MIPS_HAS_MIPS64
+#ifdef TARGET_MIPS64
case OPC_DSLLV:
gen_op_dsllv();
opn = "dsllv";
@@ -1096,13 +1205,20 @@
opn = "dsrav";
break;
case OPC_DSRLV:
- if ((ctx->opcode >> 6) & 1) {
+ switch ((ctx->opcode >> 6) & 0x1f) {
+ case 0:
+ gen_op_dsrlv();
+ opn = "dsrlv";
+ break;
+ case 1:
gen_op_drotrv();
opn = "drotrv";
- } else {
- gen_op_dsrlv();
- opn = "dsrlv";
- }
+ break;
+ default:
+ MIPS_INVAL("invalid dsrlv flag");
+ generate_exception(ctx, EXCP_RI);
+ break;
+ }
break;
#endif
default:
@@ -1178,7 +1294,7 @@
gen_op_multu();
opn = "multu";
break;
-#ifdef MIPS_HAS_MIPS64
+#ifdef TARGET_MIPS64
case OPC_DDIV:
gen_op_ddiv();
opn = "ddiv";
@@ -1239,7 +1355,7 @@
gen_op_clz();
opn = "clz";
break;
-#ifdef MIPS_HAS_MIPS64
+#ifdef TARGET_MIPS64
case OPC_DCLO:
gen_op_dclo();
opn = "dclo";
@@ -1366,24 +1482,32 @@
gen_op_goto_tb1(TBPARAM(tb));
gen_op_save_pc(dest);
gen_op_set_T0((long)tb + n);
- gen_op_exit_tb();
} else {
gen_op_save_pc(dest);
- gen_op_set_T0(0);
- gen_op_exit_tb();
+ gen_op_reset_T0();
}
+ gen_op_exit_tb();
}
/* Branches (before delay slot) */
static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
int rs, int rt, int32_t offset)
{
- target_ulong btarget;
- int blink, bcond;
+ target_ulong btarget = -1;
+ int blink = 0;
+ int bcond = 0;
- btarget = -1;
- blink = 0;
- bcond = 0;
+ if (ctx->hflags & MIPS_HFLAG_BMASK) {
+ if (loglevel & CPU_LOG_TB_IN_ASM) {
+ fprintf(logfile,
+ "Branch in delay slot at PC 0x" TARGET_FMT_lx "\n",
+ ctx->pc);
+ }
+ MIPS_INVAL("branch/jump in bdelay slot");
+ generate_exception(ctx, EXCP_RI);
+ return;
+ }
+
/* Load needed operands */
switch (opc) {
case OPC_BEQ:
@@ -1427,7 +1551,7 @@
/* Jump to register */
if (offset != 0 && offset != 16) {
/* Hint = 0 is JR/JALR, hint 16 is JR.HB/JALR.HB, the
- others are reserved. */
+ others are reserved. */
generate_exception(ctx, EXCP_RI);
return;
}
@@ -1467,18 +1591,21 @@
case OPC_BLTZAL: /* 0 < 0 */
gen_op_set_T0(ctx->pc + 8);
gen_op_store_T0_gpr(31);
+ MIPS_DEBUG("bnever and link");
return;
case OPC_BLTZALL: /* 0 < 0 likely */
gen_op_set_T0(ctx->pc + 8);
gen_op_store_T0_gpr(31);
- gen_goto_tb(ctx, 0, ctx->pc + 4);
+ /* Skip the instruction in the delay slot */
+ MIPS_DEBUG("bnever, link and skip");
+ ctx->pc += 4;
return;
case OPC_BNEL: /* rx != rx likely */
case OPC_BGTZL: /* 0 > 0 likely */
case OPC_BLTZL: /* 0 < 0 likely */
/* Skip the instruction in the delay slot */
MIPS_DEBUG("bnever and skip");
- gen_goto_tb(ctx, 0, ctx->pc + 4);
+ ctx->pc += 4;
return;
case OPC_J:
ctx->hflags |= MIPS_HFLAG_B;
@@ -1573,6 +1700,7 @@
MIPS_DEBUG("bltzal %s, %08x", regnames[rs], btarget);
not_likely:
ctx->hflags |= MIPS_HFLAG_BC;
+ gen_op_set_bcond();
break;
case OPC_BLTZALL:
gen_op_ltz();
@@ -1580,9 +1708,14 @@
MIPS_DEBUG("bltzall %s, %08x", regnames[rs], btarget);
likely:
ctx->hflags |= MIPS_HFLAG_BL;
+ gen_op_set_bcond();
+ gen_op_save_bcond();
break;
+ default:
+ MIPS_INVAL("conditional branch/jump");
+ generate_exception(ctx, EXCP_RI);
+ return;
}
- gen_op_set_bcond();
}
MIPS_DEBUG("enter ds: link %d cond %02x target %08x",
blink, ctx->hflags, btarget);
@@ -1591,7 +1724,6 @@
gen_op_set_T0(ctx->pc + 8);
gen_op_store_T0_gpr(blink);
}
- return;
}
/* special3 bitfield operations */
@@ -1621,25 +1753,25 @@
case OPC_INS:
if (lsb > msb)
goto fail;
- GEN_LOAD_REG_TN(T2, rt);
+ GEN_LOAD_REG_TN(T0, rt);
gen_op_ins(lsb, msb - lsb + 1);
break;
case OPC_DINSM:
if (lsb > msb)
goto fail;
- GEN_LOAD_REG_TN(T2, rt);
+ GEN_LOAD_REG_TN(T0, rt);
gen_op_ins(lsb, msb - lsb + 1 + 32);
break;
case OPC_DINSU:
if (lsb > msb)
goto fail;
- GEN_LOAD_REG_TN(T2, rt);
+ GEN_LOAD_REG_TN(T0, rt);
gen_op_ins(lsb + 32, msb - lsb + 1);
break;
case OPC_DINS:
if (lsb > msb)
goto fail;
- GEN_LOAD_REG_TN(T2, rt);
+ GEN_LOAD_REG_TN(T0, rt);
gen_op_ins(lsb, msb - lsb + 1);
break;
default:
@@ -1660,21 +1792,21 @@
case 0:
switch (sel) {
case 0:
- gen_op_mfc0_index();
+ gen_op_mfc0_index();
rn = "Index";
break;
case 1:
-// gen_op_mfc0_mvpcontrol(); /* MT ASE */
+// gen_op_mfc0_mvpcontrol(); /* MT ASE */
rn = "MVPControl";
-// break;
+// break;
case 2:
-// gen_op_mfc0_mvpconf0(); /* MT ASE */
+// gen_op_mfc0_mvpconf0(); /* MT ASE */
rn = "MVPConf0";
-// break;
+// break;
case 3:
-// gen_op_mfc0_mvpconf1(); /* MT ASE */
+// gen_op_mfc0_mvpconf1(); /* MT ASE */
rn = "MVPConf1";
-// break;
+// break;
default:
goto die;
}
@@ -1684,35 +1816,35 @@
case 0:
gen_op_mfc0_random();
rn = "Random";
- break;
+ break;
case 1:
-// gen_op_mfc0_vpecontrol(); /* MT ASE */
+// gen_op_mfc0_vpecontrol(); /* MT ASE */
rn = "VPEControl";
-// break;
+// break;
case 2:
-// gen_op_mfc0_vpeconf0(); /* MT ASE */
+// gen_op_mfc0_vpeconf0(); /* MT ASE */
rn = "VPEConf0";
-// break;
+// break;
case 3:
-// gen_op_mfc0_vpeconf1(); /* MT ASE */
+// gen_op_mfc0_vpeconf1(); /* MT ASE */
rn = "VPEConf1";
-// break;
+// break;
case 4:
-// gen_op_mfc0_YQMask(); /* MT ASE */
+// gen_op_mfc0_YQMask(); /* MT ASE */
rn = "YQMask";
-// break;
+// break;
case 5:
-// gen_op_mfc0_vpeschedule(); /* MT ASE */
+// gen_op_mfc0_vpeschedule(); /* MT ASE */
rn = "VPESchedule";
-// break;
+// break;
case 6:
-// gen_op_mfc0_vpeschefback(); /* MT ASE */
+// gen_op_mfc0_vpeschefback(); /* MT ASE */
rn = "VPEScheFBack";
-// break;
+// break;
case 7:
-// gen_op_mfc0_vpeopt(); /* MT ASE */
+// gen_op_mfc0_vpeopt(); /* MT ASE */
rn = "VPEOpt";
-// break;
+// break;
default:
goto die;
}
@@ -1720,37 +1852,37 @@
case 2:
switch (sel) {
case 0:
- gen_op_mfc0_entrylo0();
- rn = "EntryLo0";
- break;
+ gen_op_mfc0_entrylo0();
+ rn = "EntryLo0";
+ break;
case 1:
-// gen_op_mfc0_tcstatus(); /* MT ASE */
- rn = "TCStatus";
-// break;
+// gen_op_mfc0_tcstatus(); /* MT ASE */
+ rn = "TCStatus";
+// break;
case 2:
-// gen_op_mfc0_tcbind(); /* MT ASE */
- rn = "TCBind";
-// break;
+// gen_op_mfc0_tcbind(); /* MT ASE */
+ rn = "TCBind";
+// break;
case 3:
-// gen_op_mfc0_tcrestart(); /* MT ASE */
- rn = "TCRestart";
-// break;
+// gen_op_mfc0_tcrestart(); /* MT ASE */
+ rn = "TCRestart";
+// break;
case 4:
-// gen_op_mfc0_tchalt(); /* MT ASE */
- rn = "TCHalt";
-// break;
+// gen_op_mfc0_tchalt(); /* MT ASE */
+ rn = "TCHalt";
+// break;
case 5:
-// gen_op_mfc0_tccontext(); /* MT ASE */
- rn = "TCContext";
-// break;
+// gen_op_mfc0_tccontext(); /* MT ASE */
+ rn = "TCContext";
+// break;
case 6:
-// gen_op_mfc0_tcschedule(); /* MT ASE */
- rn = "TCSchedule";
-// break;
+// gen_op_mfc0_tcschedule(); /* MT ASE */
+ rn = "TCSchedule";
+// break;
case 7:
-// gen_op_mfc0_tcschefback(); /* MT ASE */
- rn = "TCScheFBack";
-// break;
+// gen_op_mfc0_tcschefback(); /* MT ASE */
+ rn = "TCScheFBack";
+// break;
default:
goto die;
}
@@ -1758,87 +1890,87 @@
case 3:
switch (sel) {
case 0:
- gen_op_mfc0_entrylo1();
- rn = "EntryLo1";
- break;
+ gen_op_mfc0_entrylo1();
+ rn = "EntryLo1";
+ break;
default:
goto die;
- }
+ }
break;
case 4:
switch (sel) {
case 0:
- gen_op_mfc0_context();
- rn = "Context";
- break;
+ gen_op_mfc0_context();
+ rn = "Context";
+ break;
case 1:
-// gen_op_mfc0_contextconfig(); /* SmartMIPS ASE */
- rn = "ContextConfig";
-// break;
+// gen_op_mfc0_contextconfig(); /* SmartMIPS ASE */
+ rn = "ContextConfig";
+// break;
default:
goto die;
- }
+ }
break;
case 5:
switch (sel) {
case 0:
- gen_op_mfc0_pagemask();
- rn = "PageMask";
- break;
+ gen_op_mfc0_pagemask();
+ rn = "PageMask";
+ break;
case 1:
- gen_op_mfc0_pagegrain();
- rn = "PageGrain";
- break;
+ gen_op_mfc0_pagegrain();
+ rn = "PageGrain";
+ break;
default:
goto die;
- }
+ }
break;
case 6:
switch (sel) {
case 0:
- gen_op_mfc0_wired();
- rn = "Wired";
- break;
+ gen_op_mfc0_wired();
+ rn = "Wired";
+ break;
case 1:
-// gen_op_mfc0_srsconf0(); /* shadow registers */
- rn = "SRSConf0";
-// break;
+// gen_op_mfc0_srsconf0(); /* shadow registers */
+ rn = "SRSConf0";
+// break;
case 2:
-// gen_op_mfc0_srsconf1(); /* shadow registers */
- rn = "SRSConf1";
-// break;
+// gen_op_mfc0_srsconf1(); /* shadow registers */
+ rn = "SRSConf1";
+// break;
case 3:
-// gen_op_mfc0_srsconf2(); /* shadow registers */
- rn = "SRSConf2";
-// break;
+// gen_op_mfc0_srsconf2(); /* shadow registers */
+ rn = "SRSConf2";
+// break;
case 4:
-// gen_op_mfc0_srsconf3(); /* shadow registers */
- rn = "SRSConf3";
-// break;
+// gen_op_mfc0_srsconf3(); /* shadow registers */
+ rn = "SRSConf3";
+// break;
case 5:
-// gen_op_mfc0_srsconf4(); /* shadow registers */
- rn = "SRSConf4";
-// break;
+// gen_op_mfc0_srsconf4(); /* shadow registers */
+ rn = "SRSConf4";
+// break;
default:
goto die;
- }
+ }
break;
case 7:
switch (sel) {
case 0:
- gen_op_mfc0_hwrena();
- rn = "HWREna";
- break;
+ gen_op_mfc0_hwrena();
+ rn = "HWREna";
+ break;
default:
goto die;
- }
+ }
break;
case 8:
switch (sel) {
case 0:
- gen_op_mfc0_badvaddr();
- rn = "BadVaddr";
- break;
+ gen_op_mfc0_badvaddr();
+ rn = "BadVaddr";
+ break;
default:
goto die;
}
@@ -1846,53 +1978,53 @@
case 9:
switch (sel) {
case 0:
- gen_op_mfc0_count();
- rn = "Count";
- break;
- /* 6,7 are implementation dependent */
+ gen_op_mfc0_count();
+ rn = "Count";
+ break;
+ /* 6,7 are implementation dependent */
default:
goto die;
- }
+ }
break;
case 10:
switch (sel) {
case 0:
- gen_op_mfc0_entryhi();
- rn = "EntryHi";
- break;
+ gen_op_mfc0_entryhi();
+ rn = "EntryHi";
+ break;
default:
goto die;
- }
+ }
break;
case 11:
switch (sel) {
case 0:
- gen_op_mfc0_compare();
- rn = "Compare";
- break;
- /* 6,7 are implementation dependent */
+ gen_op_mfc0_compare();
+ rn = "Compare";
+ break;
+ /* 6,7 are implementation dependent */
default:
goto die;
- }
+ }
break;
case 12:
switch (sel) {
case 0:
- gen_op_mfc0_status();
- rn = "Status";
- break;
+ gen_op_mfc0_status();
+ rn = "Status";
+ break;
case 1:
- gen_op_mfc0_intctl();
- rn = "IntCtl";
- break;
+ gen_op_mfc0_intctl();
+ rn = "IntCtl";
+ break;
case 2:
- gen_op_mfc0_srsctl();
- rn = "SRSCtl";
- break;
+ gen_op_mfc0_srsctl();
+ rn = "SRSCtl";
+ break;
case 3:
-// gen_op_mfc0_srsmap(); /* shadow registers */
- rn = "SRSMap";
-// break;
+// gen_op_mfc0_srsmap(); /* shadow registers */
+ rn = "SRSMap";
+// break;
default:
goto die;
}
@@ -1900,9 +2032,9 @@
case 13:
switch (sel) {
case 0:
- gen_op_mfc0_cause();
- rn = "Cause";
- break;
+ gen_op_mfc0_cause();
+ rn = "Cause";
+ break;
default:
goto die;
}
@@ -1910,23 +2042,23 @@
case 14:
switch (sel) {
case 0:
- gen_op_mfc0_epc();
- rn = "EPC";
- break;
+ gen_op_mfc0_epc();
+ rn = "EPC";
+ break;
default:
goto die;
- }
+ }
break;
case 15:
switch (sel) {
case 0:
- gen_op_mfc0_prid();
- rn = "PRid";
- break;
+ gen_op_mfc0_prid();
+ rn = "PRid";
+ break;
case 1:
- gen_op_mfc0_ebase();
- rn = "EBase";
- break;
+ gen_op_mfc0_ebase();
+ rn = "EBase";
+ break;
default:
goto die;
}
@@ -1934,22 +2066,31 @@
case 16:
switch (sel) {
case 0:
- gen_op_mfc0_config0();
+ gen_op_mfc0_config0();
rn = "Config";
break;
case 1:
- gen_op_mfc0_config1();
+ gen_op_mfc0_config1();
rn = "Config1";
break;
case 2:
- gen_op_mfc0_config2();
+ gen_op_mfc0_config2();
rn = "Config2";
break;
case 3:
- gen_op_mfc0_config3();
+ gen_op_mfc0_config3();
rn = "Config3";
break;
- /* 6,7 are implementation dependent */
+ /* 4,5 are reserved */
+ /* 6,7 are implementation dependent */
+ case 6:
+ gen_op_mfc0_config6();
+ rn = "Config6";
+ break;
+ case 7:
+ gen_op_mfc0_config7();
+ rn = "Config7";
+ break;
default:
goto die;
}
@@ -1957,9 +2098,9 @@
case 17:
switch (sel) {
case 0:
- gen_op_mfc0_lladdr();
- rn = "LLAddr";
- break;
+ gen_op_mfc0_lladdr();
+ rn = "LLAddr";
+ break;
default:
goto die;
}
@@ -1967,37 +2108,37 @@
case 18:
switch (sel) {
case 0:
- gen_op_mfc0_watchlo0();
- rn = "WatchLo";
- break;
+ gen_op_mfc0_watchlo0();
+ rn = "WatchLo";
+ break;
case 1:
-// gen_op_mfc0_watchlo1();
- rn = "WatchLo1";
-// break;
+// gen_op_mfc0_watchlo1();
+ rn = "WatchLo1";
+// break;
case 2:
-// gen_op_mfc0_watchlo2();
- rn = "WatchLo2";
-// break;
+// gen_op_mfc0_watchlo2();
+ rn = "WatchLo2";
+// break;
case 3:
-// gen_op_mfc0_watchlo3();
- rn = "WatchLo3";
-// break;
+// gen_op_mfc0_watchlo3();
+ rn = "WatchLo3";
+// break;
case 4:
-// gen_op_mfc0_watchlo4();
- rn = "WatchLo4";
-// break;
+// gen_op_mfc0_watchlo4();
+ rn = "WatchLo4";
+// break;
case 5:
-// gen_op_mfc0_watchlo5();
- rn = "WatchLo5";
-// break;
+// gen_op_mfc0_watchlo5();
+ rn = "WatchLo5";
+// break;
case 6:
-// gen_op_mfc0_watchlo6();
- rn = "WatchLo6";
-// break;
+// gen_op_mfc0_watchlo6();
+ rn = "WatchLo6";
+// break;
case 7:
-// gen_op_mfc0_watchlo7();
- rn = "WatchLo7";
-// break;
+// gen_op_mfc0_watchlo7();
+ rn = "WatchLo7";
+// break;
default:
goto die;
}
@@ -2005,37 +2146,37 @@
case 19:
switch (sel) {
case 0:
- gen_op_mfc0_watchhi0();
- rn = "WatchHi";
- break;
+ gen_op_mfc0_watchhi0();
+ rn = "WatchHi";
+ break;
case 1:
-// gen_op_mfc0_watchhi1();
- rn = "WatchHi1";
-// break;
+// gen_op_mfc0_watchhi1();
+ rn = "WatchHi1";
+// break;
case 2:
-// gen_op_mfc0_watchhi2();
- rn = "WatchHi2";
-// break;
+// gen_op_mfc0_watchhi2();
+ rn = "WatchHi2";
+// break;
case 3:
-// gen_op_mfc0_watchhi3();
- rn = "WatchHi3";
-// break;
+// gen_op_mfc0_watchhi3();
+ rn = "WatchHi3";
+// break;
case 4:
-// gen_op_mfc0_watchhi4();
- rn = "WatchHi4";
-// break;
+// gen_op_mfc0_watchhi4();
+ rn = "WatchHi4";
+// break;
case 5:
-// gen_op_mfc0_watchhi5();
- rn = "WatchHi5";
-// break;
+// gen_op_mfc0_watchhi5();
+ rn = "WatchHi5";
+// break;
case 6:
-// gen_op_mfc0_watchhi6();
- rn = "WatchHi6";
-// break;
+// gen_op_mfc0_watchhi6();
+ rn = "WatchHi6";
+// break;
case 7:
-// gen_op_mfc0_watchhi7();
- rn = "WatchHi7";
-// break;
+// gen_op_mfc0_watchhi7();
+ rn = "WatchHi7";
+// break;
default:
goto die;
}
@@ -2043,10 +2184,10 @@
case 20:
switch (sel) {
case 0:
- /* 64 bit MMU only */
- gen_op_mfc0_xcontext();
- rn = "XContext";
- break;
+ /* 64 bit MMU only */
+ gen_op_mfc0_xcontext();
+ rn = "XContext";
+ break;
default:
goto die;
}
@@ -2055,39 +2196,39 @@
/* Officially reserved, but sel 0 is used for R1x000 framemask */
switch (sel) {
case 0:
- gen_op_mfc0_framemask();
- rn = "Framemask";
- break;
+ gen_op_mfc0_framemask();
+ rn = "Framemask";
+ break;
default:
goto die;
}
break;
case 22:
- /* ignored */
- rn = "'Diagnostic"; /* implementation dependent */
- break;
+ /* ignored */
+ rn = "'Diagnostic"; /* implementation dependent */
+ break;
case 23:
switch (sel) {
case 0:
- gen_op_mfc0_debug(); /* EJTAG support */
- rn = "Debug";
- break;
+ gen_op_mfc0_debug(); /* EJTAG support */
+ rn = "Debug";
+ break;
case 1:
-// gen_op_mfc0_tracecontrol(); /* PDtrace support */
- rn = "TraceControl";
-// break;
+// gen_op_mfc0_tracecontrol(); /* PDtrace support */
+ rn = "TraceControl";
+// break;
case 2:
-// gen_op_mfc0_tracecontrol2(); /* PDtrace support */
- rn = "TraceControl2";
-// break;
+// gen_op_mfc0_tracecontrol2(); /* PDtrace support */
+ rn = "TraceControl2";
+// break;
case 3:
-// gen_op_mfc0_usertracedata(); /* PDtrace support */
- rn = "UserTraceData";
-// break;
+// gen_op_mfc0_usertracedata(); /* PDtrace support */
+ rn = "UserTraceData";
+// break;
case 4:
-// gen_op_mfc0_debug(); /* PDtrace support */
- rn = "TraceBPC";
-// break;
+// gen_op_mfc0_debug(); /* PDtrace support */
+ rn = "TraceBPC";
+// break;
default:
goto die;
}
@@ -2095,9 +2236,9 @@
case 24:
switch (sel) {
case 0:
- gen_op_mfc0_depc(); /* EJTAG support */
- rn = "DEPC";
- break;
+ gen_op_mfc0_depc(); /* EJTAG support */
+ rn = "DEPC";
+ break;
default:
goto die;
}
@@ -2105,37 +2246,37 @@
case 25:
switch (sel) {
case 0:
- gen_op_mfc0_performance0();
- rn = "Performance0";
+ gen_op_mfc0_performance0();
+ rn = "Performance0";
break;
case 1:
-// gen_op_mfc0_performance1();
- rn = "Performance1";
-// break;
+// gen_op_mfc0_performance1();
+ rn = "Performance1";
+// break;
case 2:
-// gen_op_mfc0_performance2();
- rn = "Performance2";
-// break;
+// gen_op_mfc0_performance2();
+ rn = "Performance2";
+// break;
case 3:
-// gen_op_mfc0_performance3();
- rn = "Performance3";
-// break;
+// gen_op_mfc0_performance3();
+ rn = "Performance3";
+// break;
case 4:
-// gen_op_mfc0_performance4();
- rn = "Performance4";
-// break;
+// gen_op_mfc0_performance4();
+ rn = "Performance4";
+// break;
case 5:
-// gen_op_mfc0_performance5();
- rn = "Performance5";
-// break;
+// gen_op_mfc0_performance5();
+ rn = "Performance5";
+// break;
case 6:
-// gen_op_mfc0_performance6();
- rn = "Performance6";
-// break;
+// gen_op_mfc0_performance6();
+ rn = "Performance6";
+// break;
case 7:
-// gen_op_mfc0_performance7();
- rn = "Performance7";
-// break;
+// gen_op_mfc0_performance7();
+ rn = "Performance7";
+// break;
default:
goto die;
}
@@ -2147,8 +2288,8 @@
switch (sel) {
/* ignored */
case 0 ... 3:
- rn = "CacheErr";
- break;
+ rn = "CacheErr";
+ break;
default:
goto die;
}
@@ -2196,9 +2337,9 @@
case 30:
switch (sel) {
case 0:
- gen_op_mfc0_errorepc();
- rn = "ErrorEPC";
- break;
+ gen_op_mfc0_errorepc();
+ rn = "ErrorEPC";
+ break;
default:
goto die;
}
@@ -2206,9 +2347,9 @@
case 31:
switch (sel) {
case 0:
- gen_op_mfc0_desave(); /* EJTAG support */
- rn = "DESAVE";
- break;
+ gen_op_mfc0_desave(); /* EJTAG support */
+ rn = "DESAVE";
+ break;
default:
goto die;
}
@@ -2246,17 +2387,17 @@
rn = "Index";
break;
case 1:
-// gen_op_mtc0_mvpcontrol(); /* MT ASE */
+// gen_op_mtc0_mvpcontrol(); /* MT ASE */
rn = "MVPControl";
-// break;
+// break;
case 2:
-// gen_op_mtc0_mvpconf0(); /* MT ASE */
+// gen_op_mtc0_mvpconf0(); /* MT ASE */
rn = "MVPConf0";
-// break;
+// break;
case 3:
-// gen_op_mtc0_mvpconf1(); /* MT ASE */
+// gen_op_mtc0_mvpconf1(); /* MT ASE */
rn = "MVPConf1";
-// break;
+// break;
default:
goto die;
}
@@ -2264,37 +2405,37 @@
case 1:
switch (sel) {
case 0:
- /* ignored */
+ /* ignored */
rn = "Random";
- break;
+ break;
case 1:
-// gen_op_mtc0_vpecontrol(); /* MT ASE */
+// gen_op_mtc0_vpecontrol(); /* MT ASE */
rn = "VPEControl";
-// break;
+// break;
case 2:
-// gen_op_mtc0_vpeconf0(); /* MT ASE */
+// gen_op_mtc0_vpeconf0(); /* MT ASE */
rn = "VPEConf0";
-// break;
+// break;
case 3:
-// gen_op_mtc0_vpeconf1(); /* MT ASE */
+// gen_op_mtc0_vpeconf1(); /* MT ASE */
rn = "VPEConf1";
-// break;
+// break;
case 4:
-// gen_op_mtc0_YQMask(); /* MT ASE */
+// gen_op_mtc0_YQMask(); /* MT ASE */
rn = "YQMask";
-// break;
+// break;
case 5:
-// gen_op_mtc0_vpeschedule(); /* MT ASE */
+// gen_op_mtc0_vpeschedule(); /* MT ASE */
rn = "VPESchedule";
-// break;
+// break;
case 6:
-// gen_op_mtc0_vpeschefback(); /* MT ASE */
+// gen_op_mtc0_vpeschefback(); /* MT ASE */
rn = "VPEScheFBack";
-// break;
+// break;
case 7:
-// gen_op_mtc0_vpeopt(); /* MT ASE */
+// gen_op_mtc0_vpeopt(); /* MT ASE */
rn = "VPEOpt";
-// break;
+// break;
default:
goto die;
}
@@ -2302,37 +2443,37 @@
case 2:
switch (sel) {
case 0:
- gen_op_mtc0_entrylo0();
- rn = "EntryLo0";
- break;
+ gen_op_mtc0_entrylo0();
+ rn = "EntryLo0";
+ break;
case 1:
-// gen_op_mtc0_tcstatus(); /* MT ASE */
- rn = "TCStatus";
-// break;
+// gen_op_mtc0_tcstatus(); /* MT ASE */
+ rn = "TCStatus";
+// break;
case 2:
-// gen_op_mtc0_tcbind(); /* MT ASE */
- rn = "TCBind";
-// break;
+// gen_op_mtc0_tcbind(); /* MT ASE */
+ rn = "TCBind";
+// break;
case 3:
-// gen_op_mtc0_tcrestart(); /* MT ASE */
- rn = "TCRestart";
-// break;
+// gen_op_mtc0_tcrestart(); /* MT ASE */
+ rn = "TCRestart";
+// break;
case 4:
-// gen_op_mtc0_tchalt(); /* MT ASE */
- rn = "TCHalt";
-// break;
+// gen_op_mtc0_tchalt(); /* MT ASE */
+ rn = "TCHalt";
+// break;
case 5:
-// gen_op_mtc0_tccontext(); /* MT ASE */
- rn = "TCContext";
-// break;
+// gen_op_mtc0_tccontext(); /* MT ASE */
+ rn = "TCContext";
+// break;
case 6:
-// gen_op_mtc0_tcschedule(); /* MT ASE */
- rn = "TCSchedule";
-// break;
+// gen_op_mtc0_tcschedule(); /* MT ASE */
+ rn = "TCSchedule";
+// break;
case 7:
-// gen_op_mtc0_tcschefback(); /* MT ASE */
- rn = "TCScheFBack";
-// break;
+// gen_op_mtc0_tcschefback(); /* MT ASE */
+ rn = "TCScheFBack";
+// break;
default:
goto die;
}
@@ -2340,80 +2481,80 @@
case 3:
switch (sel) {
case 0:
- gen_op_mtc0_entrylo1();
- rn = "EntryLo1";
- break;
+ gen_op_mtc0_entrylo1();
+ rn = "EntryLo1";
+ break;
default:
goto die;
- }
+ }
break;
case 4:
switch (sel) {
case 0:
- gen_op_mtc0_context();
- rn = "Context";
- break;
+ gen_op_mtc0_context();
+ rn = "Context";
+ break;
case 1:
-// gen_op_mtc0_contextconfig(); /* SmartMIPS ASE */
- rn = "ContextConfig";
-// break;
+// gen_op_mtc0_contextconfig(); /* SmartMIPS ASE */
+ rn = "ContextConfig";
+// break;
default:
goto die;
- }
+ }
break;
case 5:
switch (sel) {
case 0:
- gen_op_mtc0_pagemask();
- rn = "PageMask";
- break;
+ gen_op_mtc0_pagemask();
+ rn = "PageMask";
+ break;
case 1:
- gen_op_mtc0_pagegrain();
- rn = "PageGrain";
- break;
+ gen_op_mtc0_pagegrain();
+ rn = "PageGrain";
+ break;
default:
goto die;
- }
+ }
break;
case 6:
switch (sel) {
case 0:
- gen_op_mtc0_wired();
- rn = "Wired";
- break;
+ gen_op_mtc0_wired();
+ rn = "Wired";
+ break;
case 1:
-// gen_op_mtc0_srsconf0(); /* shadow registers */
- rn = "SRSConf0";
-// break;
+// gen_op_mtc0_srsconf0(); /* shadow registers */
+ rn = "SRSConf0";
+// break;
case 2:
-// gen_op_mtc0_srsconf1(); /* shadow registers */
- rn = "SRSConf1";
-// break;
+// gen_op_mtc0_srsconf1(); /* shadow registers */
+ rn = "SRSConf1";
+// break;
case 3:
-// gen_op_mtc0_srsconf2(); /* shadow registers */
- rn = "SRSConf2";
-// break;
+// gen_op_mtc0_srsconf2(); /* shadow registers */
+ rn = "SRSConf2";
+// break;
case 4:
-// gen_op_mtc0_srsconf3(); /* shadow registers */
- rn = "SRSConf3";
-// break;
+// gen_op_mtc0_srsconf3(); /* shadow registers */
+ rn = "SRSConf3";
+// break;
case 5:
-// gen_op_mtc0_srsconf4(); /* shadow registers */
- rn = "SRSConf4";
-// break;
+// gen_op_mtc0_srsconf4(); /* shadow registers */
+ rn = "SRSConf4";
+// break;
default:
goto die;
- }
+ }
break;
case 7:
switch (sel) {
case 0:
- gen_op_mtc0_hwrena();
- rn = "HWREna";
- break;
+ gen_op_mtc0_hwrena();
+ rn = "HWREna";
+ break;
default:
goto die;
- }
+ }
break;
case 8:
/* ignored */
@@ -2422,131 +2563,142 @@
case 9:
switch (sel) {
case 0:
- gen_op_mtc0_count();
- rn = "Count";
- break;
- /* 6,7 are implementation dependent */
+ gen_op_mtc0_count();
+ rn = "Count";
+ break;
+ /* 6,7 are implementation dependent */
default:
goto die;
- }
- /* Stop translation as we may have switched the execution mode */
- ctx->bstate = BS_STOP;
+ }
+ /* Stop translation as we may have switched the execution mode */
+ ctx->bstate = BS_STOP;
break;
case 10:
switch (sel) {
case 0:
- gen_op_mtc0_entryhi();
- rn = "EntryHi";
- break;
+ gen_op_mtc0_entryhi();
+ rn = "EntryHi";
+ break;
default:
goto die;
- }
+ }
break;
case 11:
switch (sel) {
case 0:
- gen_op_mtc0_compare();
- rn = "Compare";
- break;
- /* 6,7 are implementation dependent */
+ gen_op_mtc0_compare();
+ rn = "Compare";
+ break;
+ /* 6,7 are implementation dependent */
default:
goto die;
- }
- /* Stop translation as we may have switched the execution mode */
- ctx->bstate = BS_STOP;
+ }
+ /* Stop translation as we may have switched the execution mode */
+ ctx->bstate = BS_STOP;
break;
case 12:
switch (sel) {
case 0:
- gen_op_mtc0_status();
- rn = "Status";
- break;
+ gen_op_mtc0_status();
+ rn = "Status";
+ break;
case 1:
- gen_op_mtc0_intctl();
- rn = "IntCtl";
- break;
+ gen_op_mtc0_intctl();
+ rn = "IntCtl";
+ break;
case 2:
- gen_op_mtc0_srsctl();
- rn = "SRSCtl";
- break;
+ gen_op_mtc0_srsctl();
+ rn = "SRSCtl";
+ break;
case 3:
-// gen_op_mtc0_srsmap(); /* shadow registers */
- rn = "SRSMap";
-// break;
+// gen_op_mtc0_srsmap(); /* shadow registers */
+ rn = "SRSMap";
+// break;
default:
goto die;
- }
- /* Stop translation as we may have switched the execution mode */
- ctx->bstate = BS_STOP;
+ }
+ /* Stop translation as we may have switched the execution mode */
+ ctx->bstate = BS_STOP;
break;
case 13:
switch (sel) {
case 0:
- gen_op_mtc0_cause();
- rn = "Cause";
- break;
+ gen_op_mtc0_cause();
+ rn = "Cause";
+ break;
default:
goto die;
- }
- /* Stop translation as we may have switched the execution mode */
- ctx->bstate = BS_STOP;
+ }
+ /* Stop translation as we may have switched the execution mode */
+ ctx->bstate = BS_STOP;
break;
case 14:
switch (sel) {
case 0:
- gen_op_mtc0_epc();
- rn = "EPC";
- break;
+ gen_op_mtc0_epc();
+ rn = "EPC";
+ break;
default:
goto die;
- }
+ }
break;
case 15:
switch (sel) {
case 0:
- /* ignored */
- rn = "PRid";
- break;
+ /* ignored */
+ rn = "PRid";
+ break;
case 1:
- gen_op_mtc0_ebase();
- rn = "EBase";
- break;
+ gen_op_mtc0_ebase();
+ rn = "EBase";
+ break;
default:
goto die;
- }
+ }
break;
case 16:
switch (sel) {
case 0:
- gen_op_mtc0_config0();
+ gen_op_mtc0_config0();
rn = "Config";
+ /* Stop translation as we may have switched the execution mode */
+ ctx->bstate = BS_STOP;
break;
case 1:
- /* ignored */
+ /* ignored, read only */
rn = "Config1";
break;
case 2:
- gen_op_mtc0_config2();
+ gen_op_mtc0_config2();
rn = "Config2";
+ /* Stop translation as we may have switched the execution mode */
+ ctx->bstate = BS_STOP;
break;
case 3:
- /* ignored */
+ /* ignored, read only */
rn = "Config3";
break;
- /* 6,7 are implementation dependent */
+ /* 4,5 are reserved */
+ /* 6,7 are implementation dependent */
+ case 6:
+ /* ignored */
+ rn = "Config6";
+ break;
+ case 7:
+ /* ignored */
+ rn = "Config7";
+ break;
default:
rn = "Invalid config selector";
goto die;
}
- /* Stop translation as we may have switched the execution mode */
- ctx->bstate = BS_STOP;
break;
case 17:
switch (sel) {
case 0:
- /* ignored */
- rn = "LLAddr";
- break;
+ /* ignored */
+ rn = "LLAddr";
+ break;
default:
goto die;
}
@@ -2554,37 +2706,37 @@
case 18:
switch (sel) {
case 0:
- gen_op_mtc0_watchlo0();
- rn = "WatchLo";
- break;
+ gen_op_mtc0_watchlo0();
+ rn = "WatchLo";
+ break;
case 1:
-// gen_op_mtc0_watchlo1();
- rn = "WatchLo1";
-// break;
+// gen_op_mtc0_watchlo1();
+ rn = "WatchLo1";
+// break;
case 2:
-// gen_op_mtc0_watchlo2();
- rn = "WatchLo2";
-// break;
+// gen_op_mtc0_watchlo2();
+ rn = "WatchLo2";
+// break;
case 3:
-// gen_op_mtc0_watchlo3();
- rn = "WatchLo3";
-// break;
+// gen_op_mtc0_watchlo3();
+ rn = "WatchLo3";
+// break;
case 4:
-// gen_op_mtc0_watchlo4();
- rn = "WatchLo4";
-// break;
+// gen_op_mtc0_watchlo4();
+ rn = "WatchLo4";
+// break;
case 5:
-// gen_op_mtc0_watchlo5();
- rn = "WatchLo5";
-// break;
+// gen_op_mtc0_watchlo5();
+ rn = "WatchLo5";
+// break;
case 6:
-// gen_op_mtc0_watchlo6();
- rn = "WatchLo6";
-// break;
+// gen_op_mtc0_watchlo6();
+ rn = "WatchLo6";
+// break;
case 7:
-// gen_op_mtc0_watchlo7();
- rn = "WatchLo7";
-// break;
+// gen_op_mtc0_watchlo7();
+ rn = "WatchLo7";
+// break;
default:
goto die;
}
@@ -2592,37 +2744,37 @@
case 19:
switch (sel) {
case 0:
- gen_op_mtc0_watchhi0();
- rn = "WatchHi";
- break;
+ gen_op_mtc0_watchhi0();
+ rn = "WatchHi";
+ break;
case 1:
-// gen_op_mtc0_watchhi1();
- rn = "WatchHi1";
-// break;
+// gen_op_mtc0_watchhi1();
+ rn = "WatchHi1";
+// break;
case 2:
-// gen_op_mtc0_watchhi2();
- rn = "WatchHi2";
-// break;
+// gen_op_mtc0_watchhi2();
+ rn = "WatchHi2";
+// break;
case 3:
-// gen_op_mtc0_watchhi3();
- rn = "WatchHi3";
-// break;
+// gen_op_mtc0_watchhi3();
+ rn = "WatchHi3";
+// break;
case 4:
-// gen_op_mtc0_watchhi4();
- rn = "WatchHi4";
-// break;
+// gen_op_mtc0_watchhi4();
+ rn = "WatchHi4";
+// break;
case 5:
-// gen_op_mtc0_watchhi5();
- rn = "WatchHi5";
-// break;
+// gen_op_mtc0_watchhi5();
+ rn = "WatchHi5";
+// break;
case 6:
-// gen_op_mtc0_watchhi6();
- rn = "WatchHi6";
-// break;
+// gen_op_mtc0_watchhi6();
+ rn = "WatchHi6";
+// break;
case 7:
-// gen_op_mtc0_watchhi7();
- rn = "WatchHi7";
-// break;
+// gen_op_mtc0_watchhi7();
+ rn = "WatchHi7";
+// break;
default:
goto die;
}
@@ -2630,10 +2782,10 @@
case 20:
switch (sel) {
case 0:
- /* 64 bit MMU only */
- gen_op_mtc0_xcontext();
- rn = "XContext";
- break;
+ /* 64 bit MMU only */
+ /* Nothing writable in lower 32 bits */
+ rn = "XContext";
+ break;
default:
goto die;
}
@@ -2642,9 +2794,9 @@
/* Officially reserved, but sel 0 is used for R1x000 framemask */
switch (sel) {
case 0:
- gen_op_mtc0_framemask();
- rn = "Framemask";
- break;
+ gen_op_mtc0_framemask();
+ rn = "Framemask";
+ break;
default:
goto die;
}
@@ -2652,41 +2804,41 @@
case 22:
/* ignored */
rn = "Diagnostic"; /* implementation dependent */
- break;
+ break;
case 23:
switch (sel) {
case 0:
- gen_op_mtc0_debug(); /* EJTAG support */
- rn = "Debug";
- break;
+ gen_op_mtc0_debug(); /* EJTAG support */
+ rn = "Debug";
+ break;
case 1:
-// gen_op_mtc0_tracecontrol(); /* PDtrace support */
- rn = "TraceControl";
-// break;
+// gen_op_mtc0_tracecontrol(); /* PDtrace support */
+ rn = "TraceControl";
+// break;
case 2:
-// gen_op_mtc0_tracecontrol2(); /* PDtrace support */
- rn = "TraceControl2";
-// break;
+// gen_op_mtc0_tracecontrol2(); /* PDtrace support */
+ rn = "TraceControl2";
+// break;
case 3:
-// gen_op_mtc0_usertracedata(); /* PDtrace support */
- rn = "UserTraceData";
-// break;
+// gen_op_mtc0_usertracedata(); /* PDtrace support */
+ rn = "UserTraceData";
+// break;
case 4:
-// gen_op_mtc0_debug(); /* PDtrace support */
- rn = "TraceBPC";
-// break;
+// gen_op_mtc0_debug(); /* PDtrace support */
+ rn = "TraceBPC";
+// break;
default:
goto die;
}
- /* Stop translation as we may have switched the execution mode */
- ctx->bstate = BS_STOP;
+ /* Stop translation as we may have switched the execution mode */
+ ctx->bstate = BS_STOP;
break;
case 24:
switch (sel) {
case 0:
- gen_op_mtc0_depc(); /* EJTAG support */
- rn = "DEPC";
- break;
+ gen_op_mtc0_depc(); /* EJTAG support */
+ rn = "DEPC";
+ break;
default:
goto die;
}
@@ -2694,51 +2846,51 @@
case 25:
switch (sel) {
case 0:
- gen_op_mtc0_performance0();
- rn = "Performance0";
- break;
+ gen_op_mtc0_performance0();
+ rn = "Performance0";
+ break;
case 1:
-// gen_op_mtc0_performance1();
- rn = "Performance1";
-// break;
+// gen_op_mtc0_performance1();
+ rn = "Performance1";
+// break;
case 2:
-// gen_op_mtc0_performance2();
- rn = "Performance2";
-// break;
+// gen_op_mtc0_performance2();
+ rn = "Performance2";
+// break;
case 3:
-// gen_op_mtc0_performance3();
- rn = "Performance3";
-// break;
+// gen_op_mtc0_performance3();
+ rn = "Performance3";
+// break;
case 4:
-// gen_op_mtc0_performance4();
- rn = "Performance4";
-// break;
+// gen_op_mtc0_performance4();
+ rn = "Performance4";
+// break;
case 5:
-// gen_op_mtc0_performance5();
- rn = "Performance5";
-// break;
+// gen_op_mtc0_performance5();
+ rn = "Performance5";
+// break;
case 6:
-// gen_op_mtc0_performance6();
- rn = "Performance6";
-// break;
+// gen_op_mtc0_performance6();
+ rn = "Performance6";
+// break;
case 7:
-// gen_op_mtc0_performance7();
- rn = "Performance7";
-// break;
+// gen_op_mtc0_performance7();
+ rn = "Performance7";
+// break;
default:
goto die;
}
break;
case 26:
- /* ignored */
+ /* ignored */
rn = "ECC";
- break;
+ break;
case 27:
switch (sel) {
case 0 ... 3:
- /* ignored */
- rn = "CacheErr";
- break;
+ /* ignored */
+ rn = "CacheErr";
+ break;
default:
goto die;
}
@@ -2756,7 +2908,7 @@
case 3:
case 5:
case 7:
- gen_op_mtc0_datalo();
+ gen_op_mtc0_datalo();
rn = "DataLo";
break;
default:
@@ -2776,7 +2928,7 @@
case 3:
case 5:
case 7:
- gen_op_mtc0_datahi();
+ gen_op_mtc0_datahi();
rn = "DataHi";
break;
default:
@@ -2787,9 +2939,9 @@
case 30:
switch (sel) {
case 0:
- gen_op_mtc0_errorepc();
- rn = "ErrorEPC";
- break;
+ gen_op_mtc0_errorepc();
+ rn = "ErrorEPC";
+ break;
default:
goto die;
}
@@ -2797,14 +2949,14 @@
case 31:
switch (sel) {
case 0:
- gen_op_mtc0_desave(); /* EJTAG support */
- rn = "DESAVE";
- break;
+ gen_op_mtc0_desave(); /* EJTAG support */
+ rn = "DESAVE";
+ break;
default:
goto die;
}
- /* Stop translation as we may have switched the execution mode */
- ctx->bstate = BS_STOP;
+ /* Stop translation as we may have switched the execution mode */
+ ctx->bstate = BS_STOP;
break;
default:
goto die;
@@ -2827,21 +2979,1189 @@
generate_exception(ctx, EXCP_RI);
}
-static void gen_cp0 (DisasContext *ctx, uint32_t opc, int rt, int rd)
+#ifdef TARGET_MIPS64
+static void gen_dmfc0 (DisasContext *ctx, int reg, int sel)
{
- const char *opn = "unk";
+ const char *rn = "invalid";
- if ((!ctx->CP0_Status & (1 << CP0St_CU0) &&
- (ctx->hflags & MIPS_HFLAG_UM)) &&
- !(ctx->hflags & MIPS_HFLAG_ERL) &&
- !(ctx->hflags & MIPS_HFLAG_EXL)) {
- if (loglevel & CPU_LOG_TB_IN_ASM) {
- fprintf(logfile, "CP0 is not usable\n");
+ switch (reg) {
+ case 0:
+ switch (sel) {
+ case 0:
+ gen_op_mfc0_index();
+ rn = "Index";
+ break;
+ case 1:
+// gen_op_dmfc0_mvpcontrol(); /* MT ASE */
+ rn = "MVPControl";
+// break;
+ case 2:
+// gen_op_dmfc0_mvpconf0(); /* MT ASE */
+ rn = "MVPConf0";
+// break;
+ case 3:
+// gen_op_dmfc0_mvpconf1(); /* MT ASE */
+ rn = "MVPConf1";
+// break;
+ default:
+ goto die;
}
- generate_exception (ctx, EXCP_CpU);
- return;
+ break;
+ case 1:
+ switch (sel) {
+ case 0:
+ gen_op_mfc0_random();
+ rn = "Random";
+ break;
+ case 1:
+// gen_op_dmfc0_vpecontrol(); /* MT ASE */
+ rn = "VPEControl";
+// break;
+ case 2:
+// gen_op_dmfc0_vpeconf0(); /* MT ASE */
+ rn = "VPEConf0";
+// break;
+ case 3:
+// gen_op_dmfc0_vpeconf1(); /* MT ASE */
+ rn = "VPEConf1";
+// break;
+ case 4:
+// gen_op_dmfc0_YQMask(); /* MT ASE */
+ rn = "YQMask";
+// break;
+ case 5:
+// gen_op_dmfc0_vpeschedule(); /* MT ASE */
+ rn = "VPESchedule";
+// break;
+ case 6:
+// gen_op_dmfc0_vpeschefback(); /* MT ASE */
+ rn = "VPEScheFBack";
+// break;
+ case 7:
+// gen_op_dmfc0_vpeopt(); /* MT ASE */
+ rn = "VPEOpt";
+// break;
+ default:
+ goto die;
+ }
+ break;
+ case 2:
+ switch (sel) {
+ case 0:
+ gen_op_dmfc0_entrylo0();
+ rn = "EntryLo0";
+ break;
+ case 1:
+// gen_op_dmfc0_tcstatus(); /* MT ASE */
+ rn = "TCStatus";
+// break;
+ case 2:
+// gen_op_dmfc0_tcbind(); /* MT ASE */
+ rn = "TCBind";
+// break;
+ case 3:
+// gen_op_dmfc0_tcrestart(); /* MT ASE */
+ rn = "TCRestart";
+// break;
+ case 4:
+// gen_op_dmfc0_tchalt(); /* MT ASE */
+ rn = "TCHalt";
+// break;
+ case 5:
+// gen_op_dmfc0_tccontext(); /* MT ASE */
+ rn = "TCContext";
+// break;
+ case 6:
+// gen_op_dmfc0_tcschedule(); /* MT ASE */
+ rn = "TCSchedule";
+// break;
+ case 7:
+// gen_op_dmfc0_tcschefback(); /* MT ASE */
+ rn = "TCScheFBack";
+// break;
+ default:
+ goto die;
+ }
+ break;
+ case 3:
+ switch (sel) {
+ case 0:
+ gen_op_dmfc0_entrylo1();
+ rn = "EntryLo1";
+ break;
+ default:
+ goto die;
+ }
+ break;
+ case 4:
+ switch (sel) {
+ case 0:
+ gen_op_dmfc0_context();
+ rn = "Context";
+ break;
+ case 1:
+// gen_op_dmfc0_contextconfig(); /* SmartMIPS ASE */
+ rn = "ContextConfig";
+// break;
+ default:
+ goto die;
+ }
+ break;
+ case 5:
+ switch (sel) {
+ case 0:
+ gen_op_mfc0_pagemask();
+ rn = "PageMask";
+ break;
+ case 1:
+ gen_op_mfc0_pagegrain();
+ rn = "PageGrain";
+ break;
+ default:
+ goto die;
+ }
+ break;
+ case 6:
+ switch (sel) {
+ case 0:
+ gen_op_mfc0_wired();
+ rn = "Wired";
+ break;
+ case 1:
+// gen_op_dmfc0_srsconf0(); /* shadow registers */
+ rn = "SRSConf0";
+// break;
+ case 2:
+// gen_op_dmfc0_srsconf1(); /* shadow registers */
+ rn = "SRSConf1";
+// break;
+ case 3:
+// gen_op_dmfc0_srsconf2(); /* shadow registers */
+ rn = "SRSConf2";
+// break;
+ case 4:
+// gen_op_dmfc0_srsconf3(); /* shadow registers */
+ rn = "SRSConf3";
+// break;
+ case 5:
+// gen_op_dmfc0_srsconf4(); /* shadow registers */
+ rn = "SRSConf4";
+// break;
+ default:
+ goto die;
+ }
+ break;
+ case 7:
+ switch (sel) {
+ case 0:
+ gen_op_mfc0_hwrena();
+ rn = "HWREna";
+ break;
+ default:
+ goto die;
+ }
+ break;
+ case 8:
+ switch (sel) {
+ case 0:
+ gen_op_dmfc0_badvaddr();
+ rn = "BadVaddr";
+ break;
+ default:
+ goto die;
+ }
+ break;
+ case 9:
+ switch (sel) {
+ case 0:
+ gen_op_mfc0_count();
+ rn = "Count";
+ break;
+ /* 6,7 are implementation dependent */
+ default:
+ goto die;
+ }
+ break;
+ case 10:
+ switch (sel) {
+ case 0:
+ gen_op_dmfc0_entryhi();
+ rn = "EntryHi";
+ break;
+ default:
+ goto die;
+ }
+ break;
+ case 11:
+ switch (sel) {
+ case 0:
+ gen_op_mfc0_compare();
+ rn = "Compare";
+ break;
+ /* 6,7 are implementation dependent */
+ default:
+ goto die;
+ }
+ break;
+ case 12:
+ switch (sel) {
+ case 0:
+ gen_op_mfc0_status();
+ rn = "Status";
+ break;
+ case 1:
+ gen_op_mfc0_intctl();
+ rn = "IntCtl";
+ break;
+ case 2:
+ gen_op_mfc0_srsctl();
+ rn = "SRSCtl";
+ break;
+ case 3:
+ gen_op_mfc0_srsmap(); /* shadow registers */
+ rn = "SRSMap";
+ break;
+ default:
+ goto die;
+ }
+ break;
+ case 13:
+ switch (sel) {
+ case 0:
+ gen_op_mfc0_cause();
+ rn = "Cause";
+ break;
+ default:
+ goto die;
+ }
+ break;
+ case 14:
+ switch (sel) {
+ case 0:
+ gen_op_dmfc0_epc();
+ rn = "EPC";
+ break;
+ default:
+ goto die;
+ }
+ break;
+ case 15:
+ switch (sel) {
+ case 0:
+ gen_op_mfc0_prid();
+ rn = "PRid";
+ break;
+ case 1:
+ gen_op_mfc0_ebase();
+ rn = "EBase";
+ break;
+ default:
+ goto die;
+ }
+ break;
+ case 16:
+ switch (sel) {
+ case 0:
+ gen_op_mfc0_config0();
+ rn = "Config";
+ break;
+ case 1:
+ gen_op_mfc0_config1();
+ rn = "Config1";
+ break;
+ case 2:
+ gen_op_mfc0_config2();
+ rn = "Config2";
+ break;
+ case 3:
+ gen_op_mfc0_config3();
+ rn = "Config3";
+ break;
+ /* 6,7 are implementation dependent */
+ default:
+ goto die;
+ }
+ break;
+ case 17:
+ switch (sel) {
+ case 0:
+ gen_op_dmfc0_lladdr();
+ rn = "LLAddr";
+ break;
+ default:
+ goto die;
+ }
+ break;
+ case 18:
+ switch (sel) {
+ case 0:
+ gen_op_dmfc0_watchlo0();
+ rn = "WatchLo";
+ break;
+ case 1:
+// gen_op_dmfc0_watchlo1();
+ rn = "WatchLo1";
+// break;
+ case 2:
+// gen_op_dmfc0_watchlo2();
+ rn = "WatchLo2";
+// break;
+ case 3:
+// gen_op_dmfc0_watchlo3();
+ rn = "WatchLo3";
+// break;
+ case 4:
+// gen_op_dmfc0_watchlo4();
+ rn = "WatchLo4";
+// break;
+ case 5:
+// gen_op_dmfc0_watchlo5();
+ rn = "WatchLo5";
+// break;
+ case 6:
+// gen_op_dmfc0_watchlo6();
+ rn = "WatchLo6";
+// break;
+ case 7:
+// gen_op_dmfc0_watchlo7();
+ rn = "WatchLo7";
+// break;
+ default:
+ goto die;
+ }
+ break;
+ case 19:
+ switch (sel) {
+ case 0:
+ gen_op_mfc0_watchhi0();
+ rn = "WatchHi";
+ break;
+ case 1:
+// gen_op_mfc0_watchhi1();
+ rn = "WatchHi1";
+// break;
+ case 2:
+// gen_op_mfc0_watchhi2();
+ rn = "WatchHi2";
+// break;
+ case 3:
+// gen_op_mfc0_watchhi3();
+ rn = "WatchHi3";
+// break;
+ case 4:
+// gen_op_mfc0_watchhi4();
+ rn = "WatchHi4";
+// break;
+ case 5:
+// gen_op_mfc0_watchhi5();
+ rn = "WatchHi5";
+// break;
+ case 6:
+// gen_op_mfc0_watchhi6();
+ rn = "WatchHi6";
+// break;
+ case 7:
+// gen_op_mfc0_watchhi7();
+ rn = "WatchHi7";
+// break;
+ default:
+ goto die;
+ }
+ break;
+ case 20:
+ switch (sel) {
+ case 0:
+ /* 64 bit MMU only */
+ gen_op_dmfc0_xcontext();
+ rn = "XContext";
+ break;
+ default:
+ goto die;
+ }
+ break;
+ case 21:
+ /* Officially reserved, but sel 0 is used for R1x000 framemask */
+ switch (sel) {
+ case 0:
+ gen_op_mfc0_framemask();
+ rn = "Framemask";
+ break;
+ default:
+ goto die;
+ }
+ break;
+ case 22:
+ /* ignored */
+ rn = "'Diagnostic"; /* implementation dependent */
+ break;
+ case 23:
+ switch (sel) {
+ case 0:
+ gen_op_mfc0_debug(); /* EJTAG support */
+ rn = "Debug";
+ break;
+ case 1:
+// gen_op_dmfc0_tracecontrol(); /* PDtrace support */
+ rn = "TraceControl";
+// break;
+ case 2:
+// gen_op_dmfc0_tracecontrol2(); /* PDtrace support */
+ rn = "TraceControl2";
+// break;
+ case 3:
+// gen_op_dmfc0_usertracedata(); /* PDtrace support */
+ rn = "UserTraceData";
+// break;
+ case 4:
+// gen_op_dmfc0_debug(); /* PDtrace support */
+ rn = "TraceBPC";
+// break;
+ default:
+ goto die;
+ }
+ break;
+ case 24:
+ switch (sel) {
+ case 0:
+ gen_op_dmfc0_depc(); /* EJTAG support */
+ rn = "DEPC";
+ break;
+ default:
+ goto die;
+ }
+ break;
+ case 25:
+ switch (sel) {
+ case 0:
+ gen_op_mfc0_performance0();
+ rn = "Performance0";
+ break;
+ case 1:
+// gen_op_dmfc0_performance1();
+ rn = "Performance1";
+// break;
+ case 2:
+// gen_op_dmfc0_performance2();
+ rn = "Performance2";
+// break;
+ case 3:
+// gen_op_dmfc0_performance3();
+ rn = "Performance3";
+// break;
+ case 4:
+// gen_op_dmfc0_performance4();
+ rn = "Performance4";
+// break;
+ case 5:
+// gen_op_dmfc0_performance5();
+ rn = "Performance5";
+// break;
+ case 6:
+// gen_op_dmfc0_performance6();
+ rn = "Performance6";
+// break;
+ case 7:
+// gen_op_dmfc0_performance7();
+ rn = "Performance7";
+// break;
+ default:
+ goto die;
+ }
+ break;
+ case 26:
+ rn = "ECC";
+ break;
+ case 27:
+ switch (sel) {
+ /* ignored */
+ case 0 ... 3:
+ rn = "CacheErr";
+ break;
+ default:
+ goto die;
+ }
+ break;
+ case 28:
+ switch (sel) {
+ case 0:
+ case 2:
+ case 4:
+ case 6:
+ gen_op_mfc0_taglo();
+ rn = "TagLo";
+ break;
+ case 1:
+ case 3:
+ case 5:
+ case 7:
+ gen_op_mfc0_datalo();
+ rn = "DataLo";
+ break;
+ default:
+ goto die;
+ }
+ break;
+ case 29:
+ switch (sel) {
+ case 0:
+ case 2:
+ case 4:
+ case 6:
+ gen_op_mfc0_taghi();
+ rn = "TagHi";
+ break;
+ case 1:
+ case 3:
+ case 5:
+ case 7:
+ gen_op_mfc0_datahi();
+ rn = "DataHi";
+ break;
+ default:
+ goto die;
+ }
+ break;
+ case 30:
+ switch (sel) {
+ case 0:
+ gen_op_dmfc0_errorepc();
+ rn = "ErrorEPC";
+ break;
+ default:
+ goto die;
+ }
+ break;
+ case 31:
+ switch (sel) {
+ case 0:
+ gen_op_mfc0_desave(); /* EJTAG support */
+ rn = "DESAVE";
+ break;
+ default:
+ goto die;
+ }
+ break;
+ default:
+ goto die;
}
+#if defined MIPS_DEBUG_DISAS
+ if (loglevel & CPU_LOG_TB_IN_ASM) {
+ fprintf(logfile, "dmfc0 %s (reg %d sel %d)\n",
+ rn, reg, sel);
+ }
+#endif
+ return;
+die:
+#if defined MIPS_DEBUG_DISAS
+ if (loglevel & CPU_LOG_TB_IN_ASM) {
+ fprintf(logfile, "dmfc0 %s (reg %d sel %d)\n",
+ rn, reg, sel);
+ }
+#endif
+ generate_exception(ctx, EXCP_RI);
+}
+
+static void gen_dmtc0 (DisasContext *ctx, int reg, int sel)
+{
+ const char *rn = "invalid";
+
+ switch (reg) {
+ case 0:
+ switch (sel) {
+ case 0:
+ gen_op_mtc0_index();
+ rn = "Index";
+ break;
+ case 1:
+// gen_op_dmtc0_mvpcontrol(); /* MT ASE */
+ rn = "MVPControl";
+// break;
+ case 2:
+// gen_op_dmtc0_mvpconf0(); /* MT ASE */
+ rn = "MVPConf0";
+// break;
+ case 3:
+// gen_op_dmtc0_mvpconf1(); /* MT ASE */
+ rn = "MVPConf1";
+// break;
+ default:
+ goto die;
+ }
+ break;
+ case 1:
+ switch (sel) {
+ case 0:
+ /* ignored */
+ rn = "Random";
+ break;
+ case 1:
+// gen_op_dmtc0_vpecontrol(); /* MT ASE */
+ rn = "VPEControl";
+// break;
+ case 2:
+// gen_op_dmtc0_vpeconf0(); /* MT ASE */
+ rn = "VPEConf0";
+// break;
+ case 3:
+// gen_op_dmtc0_vpeconf1(); /* MT ASE */
+ rn = "VPEConf1";
+// break;
+ case 4:
+// gen_op_dmtc0_YQMask(); /* MT ASE */
+ rn = "YQMask";
+// break;
+ case 5:
+// gen_op_dmtc0_vpeschedule(); /* MT ASE */
+ rn = "VPESchedule";
+// break;
+ case 6:
+// gen_op_dmtc0_vpeschefback(); /* MT ASE */
+ rn = "VPEScheFBack";
+// break;
+ case 7:
+// gen_op_dmtc0_vpeopt(); /* MT ASE */
+ rn = "VPEOpt";
+// break;
+ default:
+ goto die;
+ }
+ break;
+ case 2:
+ switch (sel) {
+ case 0:
+ gen_op_dmtc0_entrylo0();
+ rn = "EntryLo0";
+ break;
+ case 1:
+// gen_op_dmtc0_tcstatus(); /* MT ASE */
+ rn = "TCStatus";
+// break;
+ case 2:
+// gen_op_dmtc0_tcbind(); /* MT ASE */
+ rn = "TCBind";
+// break;
+ case 3:
+// gen_op_dmtc0_tcrestart(); /* MT ASE */
+ rn = "TCRestart";
+// break;
+ case 4:
+// gen_op_dmtc0_tchalt(); /* MT ASE */
+ rn = "TCHalt";
+// break;
+ case 5:
+// gen_op_dmtc0_tccontext(); /* MT ASE */
+ rn = "TCContext";
+// break;
+ case 6:
+// gen_op_dmtc0_tcschedule(); /* MT ASE */
+ rn = "TCSchedule";
+// break;
+ case 7:
+// gen_op_dmtc0_tcschefback(); /* MT ASE */
+ rn = "TCScheFBack";
+// break;
+ default:
+ goto die;
+ }
+ break;
+ case 3:
+ switch (sel) {
+ case 0:
+ gen_op_dmtc0_entrylo1();
+ rn = "EntryLo1";
+ break;
+ default:
+ goto die;
+ }
+ break;
+ case 4:
+ switch (sel) {
+ case 0:
+ gen_op_dmtc0_context();
+ rn = "Context";
+ break;
+ case 1:
+// gen_op_dmtc0_contextconfig(); /* SmartMIPS ASE */
+ rn = "ContextConfig";
+// break;
+ default:
+ goto die;
+ }
+ break;
+ case 5:
+ switch (sel) {
+ case 0:
+ gen_op_mtc0_pagemask();
+ rn = "PageMask";
+ break;
+ case 1:
+ gen_op_mtc0_pagegrain();
+ rn = "PageGrain";
+ break;
+ default:
+ goto die;
+ }
+ break;
+ case 6:
+ switch (sel) {
+ case 0:
+ gen_op_mtc0_wired();
+ rn = "Wired";
+ break;
+ case 1:
+// gen_op_dmtc0_srsconf0(); /* shadow registers */
+ rn = "SRSConf0";
+// break;
+ case 2:
+// gen_op_dmtc0_srsconf1(); /* shadow registers */
+ rn = "SRSConf1";
+// break;
+ case 3:
+// gen_op_dmtc0_srsconf2(); /* shadow registers */
+ rn = "SRSConf2";
+// break;
+ case 4:
+// gen_op_dmtc0_srsconf3(); /* shadow registers */
+ rn = "SRSConf3";
+// break;
+ case 5:
+// gen_op_dmtc0_srsconf4(); /* shadow registers */
+ rn = "SRSConf4";
+// break;
+ default:
+ goto die;
+ }
+ break;
+ case 7:
+ switch (sel) {
+ case 0:
+ gen_op_mtc0_hwrena();
+ rn = "HWREna";
+ break;
+ default:
+ goto die;
+ }
+ break;
+ case 8:
+ /* ignored */
+ rn = "BadVaddr";
+ break;
+ case 9:
+ switch (sel) {
+ case 0:
+ gen_op_mtc0_count();
+ rn = "Count";
+ break;
+ /* 6,7 are implementation dependent */
+ default:
+ goto die;
+ }
+ /* Stop translation as we may have switched the execution mode */
+ ctx->bstate = BS_STOP;
+ break;
+ case 10:
+ switch (sel) {
+ case 0:
+ gen_op_mtc0_entryhi();
+ rn = "EntryHi";
+ break;
+ default:
+ goto die;
+ }
+ break;
+ case 11:
+ switch (sel) {
+ case 0:
+ gen_op_mtc0_compare();
+ rn = "Compare";
+ break;
+ /* 6,7 are implementation dependent */
+ default:
+ goto die;
+ }
+ /* Stop translation as we may have switched the execution mode */
+ ctx->bstate = BS_STOP;
+ break;
+ case 12:
+ switch (sel) {
+ case 0:
+ gen_op_mtc0_status();
+ rn = "Status";
+ break;
+ case 1:
+ gen_op_mtc0_intctl();
+ rn = "IntCtl";
+ break;
+ case 2:
+ gen_op_mtc0_srsctl();
+ rn = "SRSCtl";
+ break;
+ case 3:
+ gen_op_mtc0_srsmap(); /* shadow registers */
+ rn = "SRSMap";
+ break;
+ default:
+ goto die;
+ }
+ /* Stop translation as we may have switched the execution mode */
+ ctx->bstate = BS_STOP;
+ break;
+ case 13:
+ switch (sel) {
+ case 0:
+ gen_op_mtc0_cause();
+ rn = "Cause";
+ break;
+ default:
+ goto die;
+ }
+ /* Stop translation as we may have switched the execution mode */
+ ctx->bstate = BS_STOP;
+ break;
+ case 14:
+ switch (sel) {
+ case 0:
+ gen_op_dmtc0_epc();
+ rn = "EPC";
+ break;
+ default:
+ goto die;
+ }
+ break;
+ case 15:
+ switch (sel) {
+ case 0:
+ /* ignored */
+ rn = "PRid";
+ break;
+ case 1:
+ gen_op_mtc0_ebase();
+ rn = "EBase";
+ break;
+ default:
+ goto die;
+ }
+ break;
+ case 16:
+ switch (sel) {
+ case 0:
+ gen_op_mtc0_config0();
+ rn = "Config";
+ /* Stop translation as we may have switched the execution mode */
+ ctx->bstate = BS_STOP;
+ break;
+ case 1:
+ /* ignored */
+ rn = "Config1";
+ break;
+ case 2:
+ gen_op_mtc0_config2();
+ rn = "Config2";
+ /* Stop translation as we may have switched the execution mode */
+ ctx->bstate = BS_STOP;
+ break;
+ case 3:
+ /* ignored */
+ rn = "Config3";
+ break;
+ /* 6,7 are implementation dependent */
+ default:
+ rn = "Invalid config selector";
+ goto die;
+ }
+ break;
+ case 17:
+ switch (sel) {
+ case 0:
+ /* ignored */
+ rn = "LLAddr";
+ break;
+ default:
+ goto die;
+ }
+ break;
+ case 18:
+ switch (sel) {
+ case 0:
+ gen_op_dmtc0_watchlo0();
+ rn = "WatchLo";
+ break;
+ case 1:
+// gen_op_dmtc0_watchlo1();
+ rn = "WatchLo1";
+// break;
+ case 2:
+// gen_op_dmtc0_watchlo2();
+ rn = "WatchLo2";
+// break;
+ case 3:
+// gen_op_dmtc0_watchlo3();
+ rn = "WatchLo3";
+// break;
+ case 4:
+// gen_op_dmtc0_watchlo4();
+ rn = "WatchLo4";
+// break;
+ case 5:
+// gen_op_dmtc0_watchlo5();
+ rn = "WatchLo5";
+// break;
+ case 6:
+// gen_op_dmtc0_watchlo6();
+ rn = "WatchLo6";
+// break;
+ case 7:
+// gen_op_dmtc0_watchlo7();
+ rn = "WatchLo7";
+// break;
+ default:
+ goto die;
+ }
+ break;
+ case 19:
+ switch (sel) {
+ case 0:
+ gen_op_mtc0_watchhi0();
+ rn = "WatchHi";
+ break;
+ case 1:
+// gen_op_dmtc0_watchhi1();
+ rn = "WatchHi1";
+// break;
+ case 2:
+// gen_op_dmtc0_watchhi2();
+ rn = "WatchHi2";
+// break;
+ case 3:
+// gen_op_dmtc0_watchhi3();
+ rn = "WatchHi3";
+// break;
+ case 4:
+// gen_op_dmtc0_watchhi4();
+ rn = "WatchHi4";
+// break;
+ case 5:
+// gen_op_dmtc0_watchhi5();
+ rn = "WatchHi5";
+// break;
+ case 6:
+// gen_op_dmtc0_watchhi6();
+ rn = "WatchHi6";
+// break;
+ case 7:
+// gen_op_dmtc0_watchhi7();
+ rn = "WatchHi7";
+// break;
+ default:
+ goto die;
+ }
+ break;
+ case 20:
+ switch (sel) {
+ case 0:
+ /* 64 bit MMU only */
+ gen_op_dmtc0_xcontext();
+ rn = "XContext";
+ break;
+ default:
+ goto die;
+ }
+ break;
+ case 21:
+ /* Officially reserved, but sel 0 is used for R1x000 framemask */
+ switch (sel) {
+ case 0:
+ gen_op_mtc0_framemask();
+ rn = "Framemask";
+ break;
+ default:
+ goto die;
+ }
+ break;
+ case 22:
+ /* ignored */
+ rn = "Diagnostic"; /* implementation dependent */
+ break;
+ case 23:
+ switch (sel) {
+ case 0:
+ gen_op_mtc0_debug(); /* EJTAG support */
+ rn = "Debug";
+ break;
+ case 1:
+// gen_op_dmtc0_tracecontrol(); /* PDtrace support */
+ rn = "TraceControl";
+// break;
+ case 2:
+// gen_op_dmtc0_tracecontrol2(); /* PDtrace support */
+ rn = "TraceControl2";
+// break;
+ case 3:
+// gen_op_dmtc0_usertracedata(); /* PDtrace support */
+ rn = "UserTraceData";
+// break;
+ case 4:
+// gen_op_dmtc0_debug(); /* PDtrace support */
+ rn = "TraceBPC";
+// break;
+ default:
+ goto die;
+ }
+ /* Stop translation as we may have switched the execution mode */
+ ctx->bstate = BS_STOP;
+ break;
+ case 24:
+ switch (sel) {
+ case 0:
+ gen_op_dmtc0_depc(); /* EJTAG support */
+ rn = "DEPC";
+ break;
+ default:
+ goto die;
+ }
+ break;
+ case 25:
+ switch (sel) {
+ case 0:
+ gen_op_mtc0_performance0();
+ rn = "Performance0";
+ break;
+ case 1:
+// gen_op_dmtc0_performance1();
+ rn = "Performance1";
+// break;
+ case 2:
+// gen_op_dmtc0_performance2();
+ rn = "Performance2";
+// break;
+ case 3:
+// gen_op_dmtc0_performance3();
+ rn = "Performance3";
+// break;
+ case 4:
+// gen_op_dmtc0_performance4();
+ rn = "Performance4";
+// break;
+ case 5:
+// gen_op_dmtc0_performance5();
+ rn = "Performance5";
+// break;
+ case 6:
+// gen_op_dmtc0_performance6();
+ rn = "Performance6";
+// break;
+ case 7:
+// gen_op_dmtc0_performance7();
+ rn = "Performance7";
+// break;
+ default:
+ goto die;
+ }
+ break;
+ case 26:
+ /* ignored */
+ rn = "ECC";
+ break;
+ case 27:
+ switch (sel) {
+ case 0 ... 3:
+ /* ignored */
+ rn = "CacheErr";
+ break;
+ default:
+ goto die;
+ }
+ break;
+ case 28:
+ switch (sel) {
+ case 0:
+ case 2:
+ case 4:
+ case 6:
+ gen_op_mtc0_taglo();
+ rn = "TagLo";
+ break;
+ case 1:
+ case 3:
+ case 5:
+ case 7:
+ gen_op_mtc0_datalo();
+ rn = "DataLo";
+ break;
+ default:
+ goto die;
+ }
+ break;
+ case 29:
+ switch (sel) {
+ case 0:
+ case 2:
+ case 4:
+ case 6:
+ gen_op_mtc0_taghi();
+ rn = "TagHi";
+ break;
+ case 1:
+ case 3:
+ case 5:
+ case 7:
+ gen_op_mtc0_datahi();
+ rn = "DataHi";
+ break;
+ default:
+ rn = "invalid sel";
+ goto die;
+ }
+ break;
+ case 30:
+ switch (sel) {
+ case 0:
+ gen_op_dmtc0_errorepc();
+ rn = "ErrorEPC";
+ break;
+ default:
+ goto die;
+ }
+ break;
+ case 31:
+ switch (sel) {
+ case 0:
+ gen_op_mtc0_desave(); /* EJTAG support */
+ rn = "DESAVE";
+ break;
+ default:
+ goto die;
+ }
+ /* Stop translation as we may have switched the execution mode */
+ ctx->bstate = BS_STOP;
+ break;
+ default:
+ goto die;
+ }
+#if defined MIPS_DEBUG_DISAS
+ if (loglevel & CPU_LOG_TB_IN_ASM) {
+ fprintf(logfile, "dmtc0 %s (reg %d sel %d)\n",
+ rn, reg, sel);
+ }
+#endif
+ return;
+
+die:
+#if defined MIPS_DEBUG_DISAS
+ if (loglevel & CPU_LOG_TB_IN_ASM) {
+ fprintf(logfile, "dmtc0 %s (reg %d sel %d)\n",
+ rn, reg, sel);
+ }
+#endif
+ generate_exception(ctx, EXCP_RI);
+}
+#endif /* TARGET_MIPS64 */
+
+static void gen_cp0 (DisasContext *ctx, uint32_t opc, int rt, int rd)
+{
+ const char *opn = "unk";
+
switch (opc) {
case OPC_MFC0:
if (rt == 0) {
@@ -2853,15 +4173,26 @@
opn = "mfc0";
break;
case OPC_MTC0:
- /* If we get an exception, we want to restart at next instruction */
- /* XXX: breaks for mtc in delay slot */
- ctx->pc += 4;
- save_cpu_state(ctx, 1);
- ctx->pc -= 4;
GEN_LOAD_REG_TN(T0, rt);
gen_mtc0(ctx, rd, ctx->opcode & 0x7);
opn = "mtc0";
break;
+#ifdef TARGET_MIPS64
+ case OPC_DMFC0:
+ if (rt == 0) {
+ /* Treat as NOP */
+ return;
+ }
+ gen_dmfc0(ctx, rd, ctx->opcode & 0x7);
+ gen_op_store_T0_gpr(rt);
+ opn = "dmfc0";
+ break;
+ case OPC_DMTC0:
+ GEN_LOAD_REG_TN(T0, rt);
+ gen_dmtc0(ctx, rd, ctx->opcode & 0x7);
+ opn = "dmtc0";
+ break;
+#endif
#if defined(MIPS_USES_R4K_TLB)
case OPC_TLBWI:
gen_op_tlbwi();
@@ -2917,11 +4248,9 @@
MIPS_DEBUG("%s %s %d", opn, regnames[rt], rd);
}
-#ifdef MIPS_USES_FPU
-
/* CP1 Branches (before delay slot) */
static void gen_compute_branch1 (DisasContext *ctx, uint32_t op,
- int32_t offset)
+ int32_t cc, int32_t offset)
{
target_ulong btarget;
@@ -2929,33 +4258,51 @@
switch (op) {
case OPC_BC1F:
- gen_op_bc1f();
- MIPS_DEBUG("bc1f " TLSZ, btarget);
+ gen_op_bc1f(cc);
+ MIPS_DEBUG("bc1f " TARGET_FMT_lx, btarget);
goto not_likely;
case OPC_BC1FL:
- gen_op_bc1f();
- MIPS_DEBUG("bc1fl " TLSZ, btarget);
+ gen_op_bc1f(cc);
+ MIPS_DEBUG("bc1fl " TARGET_FMT_lx, btarget);
goto likely;
case OPC_BC1T:
- gen_op_bc1t();
- MIPS_DEBUG("bc1t " TLSZ, btarget);
- not_likely:
- ctx->hflags |= MIPS_HFLAG_BC;
- break;
+ gen_op_bc1t(cc);
+ MIPS_DEBUG("bc1t " TARGET_FMT_lx, btarget);
+ goto not_likely;
case OPC_BC1TL:
- gen_op_bc1t();
- MIPS_DEBUG("bc1tl " TLSZ, btarget);
+ gen_op_bc1t(cc);
+ MIPS_DEBUG("bc1tl " TARGET_FMT_lx, btarget);
likely:
ctx->hflags |= MIPS_HFLAG_BL;
+ gen_op_set_bcond();
+ gen_op_save_bcond();
break;
- default:
- MIPS_INVAL("cp1 branch/jump");
- generate_exception_err (ctx, EXCP_RI, 1);
+ case OPC_BC1FANY2:
+ gen_op_bc1fany2(cc);
+ MIPS_DEBUG("bc1fany2 " TARGET_FMT_lx, btarget);
+ goto not_likely;
+ case OPC_BC1TANY2:
+ gen_op_bc1tany2(cc);
+ MIPS_DEBUG("bc1tany2 " TARGET_FMT_lx, btarget);
+ goto not_likely;
+ case OPC_BC1FANY4:
+ gen_op_bc1fany4(cc);
+ MIPS_DEBUG("bc1fany4 " TARGET_FMT_lx, btarget);
+ goto not_likely;
+ case OPC_BC1TANY4:
+ gen_op_bc1tany4(cc);
+ MIPS_DEBUG("bc1tany4 " TARGET_FMT_lx, btarget);
+ not_likely:
+ ctx->hflags |= MIPS_HFLAG_BC;
+ gen_op_set_bcond();
+ break;
+ default:
+ MIPS_INVAL("cp1 branch");
+ generate_exception (ctx, EXCP_RI);
return;
}
- gen_op_set_bcond();
- MIPS_DEBUG("enter ds: cond %02x target " TLSZ,
+ MIPS_DEBUG("enter ds: cond %02x target " TARGET_FMT_lx,
ctx->hflags, btarget);
ctx->btarget = btarget;
@@ -2963,6 +4310,29 @@
}
/* Coprocessor 1 (FPU) */
+
+/* verify if floating point register is valid; an operation is not defined
+ * if bit 0 of any register specification is set and the FR bit in the
+ * Status register equals zero, since the register numbers specify an
+ * even-odd pair of adjacent coprocessor general registers. When the FR bit
+ * in the Status register equals one, both even and odd register numbers
+ * are valid. This limitation exists only for 64 bit wide (d,l,ps) registers.
+ *
+ * Multiple 64 bit wide registers can be checked by calling
+ * CHECK_FR(ctx, freg1 | freg2 | ... | fregN);
+ *
+ * FIXME: This is broken for R2, it needs to be checked at runtime, not
+ * at translation time.
+ */
+#define CHECK_FR(ctx, freg) do { \
+ if (!((ctx)->CP0_Status & (1 << CP0St_FR)) && ((freg) & 1)) { \
+ generate_exception (ctx, EXCP_RI); \
+ return; \
+ } \
+ } while(0)
+
+#define FOP(func, fmt) (((fmt) << 21) | (func))
+
static void gen_cp1 (DisasContext *ctx, uint32_t opc, int rt, int fs)
{
const char *opn = "unk";
@@ -2981,59 +4351,93 @@
opn = "mtc1";
break;
case OPC_CFC1:
- if (fs != 0 && fs != 31) {
- MIPS_INVAL("cfc1 freg");
- generate_exception_err (ctx, EXCP_RI, 1);
- return;
- }
GEN_LOAD_IMM_TN(T1, fs);
gen_op_cfc1();
GEN_STORE_TN_REG(rt, T0);
opn = "cfc1";
break;
case OPC_CTC1:
- if (fs != 0 && fs != 31) {
- MIPS_INVAL("ctc1 freg");
- generate_exception_err (ctx, EXCP_RI, 1);
- return;
- }
GEN_LOAD_IMM_TN(T1, fs);
GEN_LOAD_REG_TN(T0, rt);
gen_op_ctc1();
opn = "ctc1";
break;
+ case OPC_DMFC1:
+ GEN_LOAD_FREG_FTN(DT0, fs);
+ gen_op_dmfc1();
+ GEN_STORE_TN_REG(rt, T0);
+ opn = "dmfc1";
+ break;
+ case OPC_DMTC1:
+ GEN_LOAD_REG_TN(T0, rt);
+ gen_op_dmtc1();
+ GEN_STORE_FTN_FREG(fs, DT0);
+ opn = "dmtc1";
+ break;
+ case OPC_MFHC1:
+ CHECK_FR(ctx, fs);
+ GEN_LOAD_FREG_FTN(WTH0, fs);
+ gen_op_mfhc1();
+ GEN_STORE_TN_REG(rt, T0);
+ opn = "mfhc1";
+ break;
+ case OPC_MTHC1:
+ CHECK_FR(ctx, fs);
+ GEN_LOAD_REG_TN(T0, rt);
+ gen_op_mthc1();
+ GEN_STORE_FTN_FREG(fs, WTH0);
+ opn = "mthc1";
+ break;
default:
if (loglevel & CPU_LOG_TB_IN_ASM) {
fprintf(logfile, "Invalid CP1 opcode: %08x %03x %03x %03x\n",
ctx->opcode, ctx->opcode >> 26, ctx->opcode & 0x3F,
((ctx->opcode >> 16) & 0x1F));
}
- generate_exception_err (ctx, EXCP_RI, 1);
+ generate_exception (ctx, EXCP_RI);
return;
}
MIPS_DEBUG("%s %s %s", opn, regnames[rt], fregnames[fs]);
}
-/* verify if floating point register is valid; an operation is not defined
- * if bit 0 of any register specification is set and the FR bit in the
- * Status register equals zero, since the register numbers specify an
- * even-odd pair of adjacent coprocessor general registers. When the FR bit
- * in the Status register equals one, both even and odd register numbers
- * are valid.
- *
- * Multiple float registers can be checked by calling
- * CHECK_FR(ctx, freg1 | freg2 | ... | fregN);
- */
-#define CHECK_FR(ctx, freg) do { \
- if (!((ctx)->CP0_Status & (1<<CP0St_FR)) && ((freg) & 1)) { \
- generate_exception_err (ctx, EXCP_RI, 1); \
- return; \
- } \
- } while(0)
+static void gen_movci (DisasContext *ctx, int rd, int rs, int cc, int tf)
+{
+ uint32_t ccbit;
-#define FOP(func, fmt) (((fmt) << 21) | (func))
+ GEN_LOAD_REG_TN(T0, rd);
+ GEN_LOAD_REG_TN(T1, rs);
+ if (cc)
+ ccbit = 1 << (24 + cc);
+ else
+ ccbit = 1 << 23;
+ if (!tf)
+ gen_op_movf(ccbit);
+ else
+ gen_op_movt(ccbit);
+ GEN_STORE_TN_REG(rd, T0);
+}
-static void gen_farith (DisasContext *ctx, uint32_t op1, int ft, int fs, int fd)
+#define GEN_MOVCF(fmt) \
+static void glue(gen_movcf_, fmt) (DisasContext *ctx, int cc, int tf) \
+{ \
+ uint32_t ccbit; \
+ \
+ if (cc) \
+ ccbit = 1 << (24 + cc); \
+ else \
+ ccbit = 1 << 23; \
+ if (!tf) \
+ glue(gen_op_float_movf_, fmt)(ccbit); \
+ else \
+ glue(gen_op_float_movt_, fmt)(ccbit); \
+}
+GEN_MOVCF(d);
+GEN_MOVCF(s);
+GEN_MOVCF(ps);
+#undef GEN_MOVCF
+
+static void gen_farith (DisasContext *ctx, uint32_t op1, int ft,
+ int fs, int fd, int cc)
{
const char *opn = "unk";
const char *condnames[] = {
@@ -3058,6 +4462,187 @@
uint32_t func = ctx->opcode & 0x3f;
switch (ctx->opcode & FOP(0x3f, 0x1f)) {
+ case FOP(0, 16):
+ GEN_LOAD_FREG_FTN(WT0, fs);
+ GEN_LOAD_FREG_FTN(WT1, ft);
+ gen_op_float_add_s();
+ GEN_STORE_FTN_FREG(fd, WT2);
+ opn = "add.s";
+ binary = 1;
+ break;
+ case FOP(1, 16):
+ GEN_LOAD_FREG_FTN(WT0, fs);
+ GEN_LOAD_FREG_FTN(WT1, ft);
+ gen_op_float_sub_s();
+ GEN_STORE_FTN_FREG(fd, WT2);
+ opn = "sub.s";
+ binary = 1;
+ break;
+ case FOP(2, 16):
+ GEN_LOAD_FREG_FTN(WT0, fs);
+ GEN_LOAD_FREG_FTN(WT1, ft);
+ gen_op_float_mul_s();
+ GEN_STORE_FTN_FREG(fd, WT2);
+ opn = "mul.s";
+ binary = 1;
+ break;
+ case FOP(3, 16):
+ GEN_LOAD_FREG_FTN(WT0, fs);
+ GEN_LOAD_FREG_FTN(WT1, ft);
+ gen_op_float_div_s();
+ GEN_STORE_FTN_FREG(fd, WT2);
+ opn = "div.s";
+ binary = 1;
+ break;
+ case FOP(4, 16):
+ GEN_LOAD_FREG_FTN(WT0, fs);
+ gen_op_float_sqrt_s();
+ GEN_STORE_FTN_FREG(fd, WT2);
+ opn = "sqrt.s";
+ break;
+ case FOP(5, 16):
+ GEN_LOAD_FREG_FTN(WT0, fs);
+ gen_op_float_abs_s();
+ GEN_STORE_FTN_FREG(fd, WT2);
+ opn = "abs.s";
+ break;
+ case FOP(6, 16):
+ GEN_LOAD_FREG_FTN(WT0, fs);
+ gen_op_float_mov_s();
+ GEN_STORE_FTN_FREG(fd, WT2);
+ opn = "mov.s";
+ break;
+ case FOP(7, 16):
+ GEN_LOAD_FREG_FTN(WT0, fs);
+ gen_op_float_chs_s();
+ GEN_STORE_FTN_FREG(fd, WT2);
+ opn = "neg.s";
+ break;
+ case FOP(8, 16):
+ CHECK_FR(ctx, fs);
+ GEN_LOAD_FREG_FTN(WT0, fs);
+ gen_op_float_roundl_s();
+ GEN_STORE_FTN_FREG(fd, DT2);
+ opn = "round.l.s";
+ break;
+ case FOP(9, 16):
+ CHECK_FR(ctx, fs);
+ GEN_LOAD_FREG_FTN(WT0, fs);
+ gen_op_float_truncl_s();
+ GEN_STORE_FTN_FREG(fd, DT2);
+ opn = "trunc.l.s";
+ break;
+ case FOP(10, 16):
+ CHECK_FR(ctx, fs);
+ GEN_LOAD_FREG_FTN(WT0, fs);
+ gen_op_float_ceill_s();
+ GEN_STORE_FTN_FREG(fd, DT2);
+ opn = "ceil.l.s";
+ break;
+ case FOP(11, 16):
+ CHECK_FR(ctx, fs);
+ GEN_LOAD_FREG_FTN(WT0, fs);
+ gen_op_float_floorl_s();
+ GEN_STORE_FTN_FREG(fd, DT2);
+ opn = "floor.l.s";
+ break;
+ case FOP(12, 16):
+ GEN_LOAD_FREG_FTN(WT0, fs);
+ gen_op_float_roundw_s();
+ GEN_STORE_FTN_FREG(fd, WT2);
+ opn = "round.w.s";
+ break;
+ case FOP(13, 16):
+ GEN_LOAD_FREG_FTN(WT0, fs);
+ gen_op_float_truncw_s();
+ GEN_STORE_FTN_FREG(fd, WT2);
+ opn = "trunc.w.s";
+ break;
+ case FOP(14, 16):
+ GEN_LOAD_FREG_FTN(WT0, fs);
+ gen_op_float_ceilw_s();
+ GEN_STORE_FTN_FREG(fd, WT2);
+ opn = "ceil.w.s";
+ break;
+ case FOP(15, 16):
+ GEN_LOAD_FREG_FTN(WT0, fs);
+ gen_op_float_floorw_s();
+ GEN_STORE_FTN_FREG(fd, WT2);
+ opn = "floor.w.s";
+ break;
+ case FOP(17, 16):
+ GEN_LOAD_REG_TN(T0, ft);
+ GEN_LOAD_FREG_FTN(WT0, fs);
+ GEN_LOAD_FREG_FTN(WT2, fd);
+ gen_movcf_s(ctx, (ft >> 2) & 0x7, ft & 0x1);
+ GEN_STORE_FTN_FREG(fd, WT2);
+ opn = "movcf.s";
+ break;
+ case FOP(18, 16):
+ GEN_LOAD_REG_TN(T0, ft);
+ GEN_LOAD_FREG_FTN(WT0, fs);
+ GEN_LOAD_FREG_FTN(WT2, fd);
+ gen_op_float_movz_s();
+ GEN_STORE_FTN_FREG(fd, WT2);
+ opn = "movz.s";
+ break;
+ case FOP(19, 16):
+ GEN_LOAD_REG_TN(T0, ft);
+ GEN_LOAD_FREG_FTN(WT0, fs);
+ GEN_LOAD_FREG_FTN(WT2, fd);
+ gen_op_float_movn_s();
+ GEN_STORE_FTN_FREG(fd, WT2);
+ opn = "movn.s";
+ break;
+ case FOP(33, 16):
+ CHECK_FR(ctx, fd);
+ GEN_LOAD_FREG_FTN(WT0, fs);
+ gen_op_float_cvtd_s();
+ GEN_STORE_FTN_FREG(fd, DT2);
+ opn = "cvt.d.s";
+ break;
+ case FOP(36, 16):
+ GEN_LOAD_FREG_FTN(WT0, fs);
+ gen_op_float_cvtw_s();
+ GEN_STORE_FTN_FREG(fd, WT2);
+ opn = "cvt.w.s";
+ break;
+ case FOP(37, 16):
+ CHECK_FR(ctx, fs | fd);
+ GEN_LOAD_FREG_FTN(WT0, fs);
+ gen_op_float_cvtl_s();
+ GEN_STORE_FTN_FREG(fd, DT2);
+ opn = "cvt.l.s";
+ break;
+ case FOP(38, 16):
+ CHECK_FR(ctx, fs | ft | fd);
+ GEN_LOAD_FREG_FTN(WT1, fs);
+ GEN_LOAD_FREG_FTN(WT0, ft);
+ gen_op_float_cvtps_s();
+ GEN_STORE_FTN_FREG(fd, DT2);
+ opn = "cvt.ps.s";
+ break;
+ case FOP(48, 16):
+ case FOP(49, 16):
+ case FOP(50, 16):
+ case FOP(51, 16):
+ case FOP(52, 16):
+ case FOP(53, 16):
+ case FOP(54, 16):
+ case FOP(55, 16):
+ case FOP(56, 16):
+ case FOP(57, 16):
+ case FOP(58, 16):
+ case FOP(59, 16):
+ case FOP(60, 16):
+ case FOP(61, 16):
+ case FOP(62, 16):
+ case FOP(63, 16):
+ GEN_LOAD_FREG_FTN(WT0, fs);
+ GEN_LOAD_FREG_FTN(WT1, ft);
+ gen_cmp_s(func-48, cc);
+ opn = condnames[func-48];
+ break;
case FOP(0, 17):
CHECK_FR(ctx, fs | ft | fd);
GEN_LOAD_FREG_FTN(DT0, fs);
@@ -3122,52 +4707,86 @@
GEN_STORE_FTN_FREG(fd, DT2);
opn = "neg.d";
break;
- /* 8 - round.l */
- /* 9 - trunc.l */
- /* 10 - ceil.l */
- /* 11 - floor.l */
+ case FOP(8, 17):
+ CHECK_FR(ctx, fs);
+ GEN_LOAD_FREG_FTN(DT0, fs);
+ gen_op_float_roundl_d();
+ GEN_STORE_FTN_FREG(fd, DT2);
+ opn = "round.l.d";
+ break;
+ case FOP(9, 17):
+ CHECK_FR(ctx, fs);
+ GEN_LOAD_FREG_FTN(DT0, fs);
+ gen_op_float_truncl_d();
+ GEN_STORE_FTN_FREG(fd, DT2);
+ opn = "trunc.l.d";
+ break;
+ case FOP(10, 17):
+ CHECK_FR(ctx, fs);
+ GEN_LOAD_FREG_FTN(DT0, fs);
+ gen_op_float_ceill_d();
+ GEN_STORE_FTN_FREG(fd, DT2);
+ opn = "ceil.l.d";
+ break;
+ case FOP(11, 17):
+ CHECK_FR(ctx, fs);
+ GEN_LOAD_FREG_FTN(DT0, fs);
+ gen_op_float_floorl_d();
+ GEN_STORE_FTN_FREG(fd, DT2);
+ opn = "floor.l.d";
+ break;
case FOP(12, 17):
- CHECK_FR(ctx, fs | fd);
+ CHECK_FR(ctx, fs);
GEN_LOAD_FREG_FTN(DT0, fs);
gen_op_float_roundw_d();
GEN_STORE_FTN_FREG(fd, WT2);
opn = "round.w.d";
break;
case FOP(13, 17):
- CHECK_FR(ctx, fs | fd);
+ CHECK_FR(ctx, fs);
GEN_LOAD_FREG_FTN(DT0, fs);
gen_op_float_truncw_d();
GEN_STORE_FTN_FREG(fd, WT2);
opn = "trunc.w.d";
break;
case FOP(14, 17):
- CHECK_FR(ctx, fs | fd);
+ CHECK_FR(ctx, fs);
GEN_LOAD_FREG_FTN(DT0, fs);
gen_op_float_ceilw_d();
GEN_STORE_FTN_FREG(fd, WT2);
opn = "ceil.w.d";
break;
case FOP(15, 17):
- CHECK_FR(ctx, fs | fd);
+ CHECK_FR(ctx, fs);
GEN_LOAD_FREG_FTN(DT0, fs);
gen_op_float_floorw_d();
GEN_STORE_FTN_FREG(fd, WT2);
opn = "floor.w.d";
break;
- case FOP(33, 16): /* cvt.d.s */
- CHECK_FR(ctx, fs | fd);
- GEN_LOAD_FREG_FTN(WT0, fs);
- gen_op_float_cvtd_s();
+ case FOP(17, 17):
+ GEN_LOAD_REG_TN(T0, ft);
+ GEN_LOAD_FREG_FTN(DT0, fs);
+ GEN_LOAD_FREG_FTN(DT2, fd);
+ gen_movcf_d(ctx, (ft >> 2) & 0x7, ft & 0x1);
GEN_STORE_FTN_FREG(fd, DT2);
- opn = "cvt.d.s";
+ opn = "movcf.d";
break;
- case FOP(33, 20): /* cvt.d.w */
- CHECK_FR(ctx, fs | fd);
- GEN_LOAD_FREG_FTN(WT0, fs);
- gen_op_float_cvtd_w();
+ case FOP(18, 17):
+ GEN_LOAD_REG_TN(T0, ft);
+ GEN_LOAD_FREG_FTN(DT0, fs);
+ GEN_LOAD_FREG_FTN(DT2, fd);
+ gen_op_float_movz_d();
GEN_STORE_FTN_FREG(fd, DT2);
- opn = "cvt.d.w";
+ opn = "movz.d";
break;
+ case FOP(19, 17):
+ GEN_LOAD_REG_TN(T0, ft);
+ GEN_LOAD_FREG_FTN(DT0, fs);
+ GEN_LOAD_FREG_FTN(DT2, fd);
+ gen_op_float_movn_d();
+ GEN_STORE_FTN_FREG(fd, DT2);
+ opn = "movn.d";
+ break;
case FOP(48, 17):
case FOP(49, 17):
case FOP(50, 17):
@@ -3187,144 +4806,246 @@
CHECK_FR(ctx, fs | ft);
GEN_LOAD_FREG_FTN(DT0, fs);
GEN_LOAD_FREG_FTN(DT1, ft);
- gen_cmp_d(func-48);
+ gen_cmp_d(func-48, cc);
opn = condnames[func-48];
break;
- case FOP(0, 16):
- CHECK_FR(ctx, fs | ft | fd);
+ case FOP(32, 17):
+ CHECK_FR(ctx, fs);
+ GEN_LOAD_FREG_FTN(DT0, fs);
+ gen_op_float_cvts_d();
+ GEN_STORE_FTN_FREG(fd, WT2);
+ opn = "cvt.s.d";
+ break;
+ case FOP(36, 17):
+ CHECK_FR(ctx, fs);
+ GEN_LOAD_FREG_FTN(DT0, fs);
+ gen_op_float_cvtw_d();
+ GEN_STORE_FTN_FREG(fd, WT2);
+ opn = "cvt.w.d";
+ break;
+ case FOP(37, 17):
+ CHECK_FR(ctx, fs | fd);
+ GEN_LOAD_FREG_FTN(DT0, fs);
+ gen_op_float_cvtl_d();
+ GEN_STORE_FTN_FREG(fd, DT2);
+ opn = "cvt.l.d";
+ break;
+ case FOP(32, 20):
GEN_LOAD_FREG_FTN(WT0, fs);
- GEN_LOAD_FREG_FTN(WT1, ft);
- gen_op_float_add_s();
+ gen_op_float_cvts_w();
GEN_STORE_FTN_FREG(fd, WT2);
- opn = "add.s";
- binary = 1;
+ opn = "cvt.s.w";
break;
- case FOP(1, 16):
+ case FOP(33, 20):
+ CHECK_FR(ctx, fd);
+ GEN_LOAD_FREG_FTN(WT0, fs);
+ gen_op_float_cvtd_w();
+ GEN_STORE_FTN_FREG(fd, DT2);
+ opn = "cvt.d.w";
+ break;
+ case FOP(32, 21):
+ CHECK_FR(ctx, fs);
+ GEN_LOAD_FREG_FTN(DT0, fs);
+ gen_op_float_cvts_l();
+ GEN_STORE_FTN_FREG(fd, WT2);
+ opn = "cvt.s.l";
+ break;
+ case FOP(33, 21):
+ CHECK_FR(ctx, fs | fd);
+ GEN_LOAD_FREG_FTN(DT0, fs);
+ gen_op_float_cvtd_l();
+ GEN_STORE_FTN_FREG(fd, DT2);
+ opn = "cvt.d.l";
+ break;
+ case FOP(38, 20):
+ case FOP(38, 21):
+ CHECK_FR(ctx, fs | fd);
+ GEN_LOAD_FREG_FTN(WT0, fs);
+ GEN_LOAD_FREG_FTN(WTH0, fs);
+ gen_op_float_cvtps_pw();
+ GEN_STORE_FTN_FREG(fd, WT2);
+ GEN_STORE_FTN_FREG(fd, WTH2);
+ opn = "cvt.ps.pw";
+ break;
+ case FOP(0, 22):
CHECK_FR(ctx, fs | ft | fd);
GEN_LOAD_FREG_FTN(WT0, fs);
+ GEN_LOAD_FREG_FTN(WTH0, fs);
GEN_LOAD_FREG_FTN(WT1, ft);
- gen_op_float_sub_s();
+ GEN_LOAD_FREG_FTN(WTH1, ft);
+ gen_op_float_add_ps();
GEN_STORE_FTN_FREG(fd, WT2);
- opn = "sub.s";
- binary = 1;
+ GEN_STORE_FTN_FREG(fd, WTH2);
+ opn = "add.ps";
break;
- case FOP(2, 16):
+ case FOP(1, 22):
CHECK_FR(ctx, fs | ft | fd);
GEN_LOAD_FREG_FTN(WT0, fs);
+ GEN_LOAD_FREG_FTN(WTH0, fs);
GEN_LOAD_FREG_FTN(WT1, ft);
- gen_op_float_mul_s();
+ GEN_LOAD_FREG_FTN(WTH1, ft);
+ gen_op_float_sub_ps();
GEN_STORE_FTN_FREG(fd, WT2);
- opn = "mul.s";
- binary = 1;
+ GEN_STORE_FTN_FREG(fd, WTH2);
+ opn = "sub.ps";
break;
- case FOP(3, 16):
+ case FOP(2, 22):
CHECK_FR(ctx, fs | ft | fd);
GEN_LOAD_FREG_FTN(WT0, fs);
+ GEN_LOAD_FREG_FTN(WTH0, fs);
GEN_LOAD_FREG_FTN(WT1, ft);
- gen_op_float_div_s();
+ GEN_LOAD_FREG_FTN(WTH1, ft);
+ gen_op_float_mul_ps();
GEN_STORE_FTN_FREG(fd, WT2);
- opn = "div.s";
- binary = 1;
+ GEN_STORE_FTN_FREG(fd, WTH2);
+ opn = "mul.ps";
break;
- case FOP(4, 16):
+ case FOP(5, 22):
CHECK_FR(ctx, fs | fd);
GEN_LOAD_FREG_FTN(WT0, fs);
- gen_op_float_sqrt_s();
+ GEN_LOAD_FREG_FTN(WTH0, fs);
+ gen_op_float_abs_ps();
GEN_STORE_FTN_FREG(fd, WT2);
- opn = "sqrt.s";
+ GEN_STORE_FTN_FREG(fd, WTH2);
+ opn = "abs.ps";
break;
- case FOP(5, 16):
+ case FOP(6, 22):
CHECK_FR(ctx, fs | fd);
GEN_LOAD_FREG_FTN(WT0, fs);
- gen_op_float_abs_s();
+ GEN_LOAD_FREG_FTN(WTH0, fs);
+ gen_op_float_mov_ps();
GEN_STORE_FTN_FREG(fd, WT2);
- opn = "abs.s";
+ GEN_STORE_FTN_FREG(fd, WTH2);
+ opn = "mov.ps";
break;
- case FOP(6, 16):
+ case FOP(7, 22):
CHECK_FR(ctx, fs | fd);
GEN_LOAD_FREG_FTN(WT0, fs);
- gen_op_float_mov_s();
+ GEN_LOAD_FREG_FTN(WTH0, fs);
+ gen_op_float_chs_ps();
GEN_STORE_FTN_FREG(fd, WT2);
- opn = "mov.s";
+ GEN_STORE_FTN_FREG(fd, WTH2);
+ opn = "neg.ps";
break;
- case FOP(7, 16):
- CHECK_FR(ctx, fs | fd);
+ case FOP(17, 22):
+ GEN_LOAD_REG_TN(T0, ft);
GEN_LOAD_FREG_FTN(WT0, fs);
- gen_op_float_chs_s();
+ GEN_LOAD_FREG_FTN(WTH0, fs);
+ GEN_LOAD_FREG_FTN(WT2, fd);
+ GEN_LOAD_FREG_FTN(WTH2, fd);
+ gen_movcf_ps(ctx, (ft >> 2) & 0x7, ft & 0x1);
GEN_STORE_FTN_FREG(fd, WT2);
- opn = "neg.s";
+ GEN_STORE_FTN_FREG(fd, WTH2);
+ opn = "movcf.ps";
break;
- case FOP(12, 16):
- CHECK_FR(ctx, fs | fd);
+ case FOP(18, 22):
+ GEN_LOAD_REG_TN(T0, ft);
GEN_LOAD_FREG_FTN(WT0, fs);
- gen_op_float_roundw_s();
+ GEN_LOAD_FREG_FTN(WTH0, fs);
+ GEN_LOAD_FREG_FTN(WT2, fd);
+ GEN_LOAD_FREG_FTN(WTH2, fd);
+ gen_op_float_movz_ps();
GEN_STORE_FTN_FREG(fd, WT2);
- opn = "round.w.s";
+ GEN_STORE_FTN_FREG(fd, WTH2);
+ opn = "movz.ps";
break;
- case FOP(13, 16):
- CHECK_FR(ctx, fs | fd);
+ case FOP(19, 22):
+ GEN_LOAD_REG_TN(T0, ft);
GEN_LOAD_FREG_FTN(WT0, fs);
- gen_op_float_truncw_s();
+ GEN_LOAD_FREG_FTN(WTH0, fs);
+ GEN_LOAD_FREG_FTN(WT2, fd);
+ GEN_LOAD_FREG_FTN(WTH2, fd);
+ gen_op_float_movn_ps();
GEN_STORE_FTN_FREG(fd, WT2);
- opn = "trunc.w.s";
+ GEN_STORE_FTN_FREG(fd, WTH2);
+ opn = "movn.ps";
break;
- case FOP(32, 17): /* cvt.s.d */
- CHECK_FR(ctx, fs | fd);
- GEN_LOAD_FREG_FTN(DT0, fs);
- gen_op_float_cvts_d();
+ case FOP(32, 22):
+ CHECK_FR(ctx, fs);
+ GEN_LOAD_FREG_FTN(WTH0, fs);
+ gen_op_float_cvts_pu();
GEN_STORE_FTN_FREG(fd, WT2);
- opn = "cvt.s.d";
+ opn = "cvt.s.pu";
break;
- case FOP(32, 20): /* cvt.s.w */
+ case FOP(36, 22):
CHECK_FR(ctx, fs | fd);
GEN_LOAD_FREG_FTN(WT0, fs);
- gen_op_float_cvts_w();
+ GEN_LOAD_FREG_FTN(WTH0, fs);
+ gen_op_float_cvtpw_ps();
GEN_STORE_FTN_FREG(fd, WT2);
- opn = "cvt.s.w";
+ GEN_STORE_FTN_FREG(fd, WTH2);
+ opn = "cvt.pw.ps";
break;
- case FOP(36, 16): /* cvt.w.s */
- CHECK_FR(ctx, fs | fd);
+ case FOP(40, 22):
+ CHECK_FR(ctx, fs);
GEN_LOAD_FREG_FTN(WT0, fs);
- gen_op_float_cvtw_s();
+ gen_op_float_cvts_pl();
GEN_STORE_FTN_FREG(fd, WT2);
- opn = "cvt.w.s";
+ opn = "cvt.s.pl";
break;
- case FOP(36, 17): /* cvt.w.d */
- CHECK_FR(ctx, fs | fd);
- GEN_LOAD_FREG_FTN(DT0, fs);
- gen_op_float_cvtw_d();
- GEN_STORE_FTN_FREG(fd, WT2);
- opn = "cvt.w.d";
+ case FOP(44, 22):
+ CHECK_FR(ctx, fs | ft | fd);
+ GEN_LOAD_FREG_FTN(WT0, fs);
+ GEN_LOAD_FREG_FTN(WT1, ft);
+ gen_op_float_pll_ps();
+ GEN_STORE_FTN_FREG(fd, DT2);
+ opn = "pll.ps";
break;
- case FOP(48, 16):
- case FOP(49, 16):
- case FOP(50, 16):
- case FOP(51, 16):
- case FOP(52, 16):
- case FOP(53, 16):
- case FOP(54, 16):
- case FOP(55, 16):
- case FOP(56, 16):
- case FOP(57, 16):
- case FOP(58, 16):
- case FOP(59, 16):
- case FOP(60, 16):
- case FOP(61, 16):
- case FOP(62, 16):
- case FOP(63, 16):
+ case FOP(45, 22):
+ CHECK_FR(ctx, fs | ft | fd);
+ GEN_LOAD_FREG_FTN(WT0, fs);
+ GEN_LOAD_FREG_FTN(WTH1, ft);
+ gen_op_float_plu_ps();
+ GEN_STORE_FTN_FREG(fd, DT2);
+ opn = "plu.ps";
+ break;
+ case FOP(46, 22):
+ CHECK_FR(ctx, fs | ft | fd);
+ GEN_LOAD_FREG_FTN(WTH0, fs);
+ GEN_LOAD_FREG_FTN(WT1, ft);
+ gen_op_float_pul_ps();
+ GEN_STORE_FTN_FREG(fd, DT2);
+ opn = "pul.ps";
+ break;
+ case FOP(47, 22):
+ CHECK_FR(ctx, fs | ft | fd);
+ GEN_LOAD_FREG_FTN(WTH0, fs);
+ GEN_LOAD_FREG_FTN(WTH1, ft);
+ gen_op_float_puu_ps();
+ GEN_STORE_FTN_FREG(fd, DT2);
+ opn = "puu.ps";
+ break;
+ case FOP(48, 22):
+ case FOP(49, 22):
+ case FOP(50, 22):
+ case FOP(51, 22):
+ case FOP(52, 22):
+ case FOP(53, 22):
+ case FOP(54, 22):
+ case FOP(55, 22):
+ case FOP(56, 22):
+ case FOP(57, 22):
+ case FOP(58, 22):
+ case FOP(59, 22):
+ case FOP(60, 22):
+ case FOP(61, 22):
+ case FOP(62, 22):
+ case FOP(63, 22):
CHECK_FR(ctx, fs | ft);
GEN_LOAD_FREG_FTN(WT0, fs);
+ GEN_LOAD_FREG_FTN(WTH0, fs);
GEN_LOAD_FREG_FTN(WT1, ft);
- gen_cmp_s(func-48);
+ GEN_LOAD_FREG_FTN(WTH1, ft);
+ gen_cmp_ps(func-48, cc);
opn = condnames[func-48];
break;
- default:
+ default:
if (loglevel & CPU_LOG_TB_IN_ASM) {
fprintf(logfile, "Invalid FP arith function: %08x %03x %03x %03x\n",
ctx->opcode, ctx->opcode >> 26, ctx->opcode & 0x3F,
((ctx->opcode >> 16) & 0x1F));
}
- generate_exception_err (ctx, EXCP_RI, 1);
+ generate_exception (ctx, EXCP_RI);
return;
}
if (binary)
@@ -3333,46 +5054,149 @@
MIPS_DEBUG("%s %s,%s", opn, fregnames[fd], fregnames[fs]);
}
-static void gen_movci (DisasContext *ctx, int rd, int rs, int cc, int tf)
+/* Coprocessor 3 (FPU) */
+static void gen_flt3_ldst (DisasContext *ctx, uint32_t opc, int fd,
+ int base, int index)
{
- uint32_t ccbit;
+ const char *opn = "unk";
- if (cc)
- ccbit = 1 << (24 + cc);
- else
- ccbit = 1 << 23;
- if (!tf)
- gen_op_movf(ccbit, rd, rs);
- else
- gen_op_movt(ccbit, rd, rs);
+ GEN_LOAD_REG_TN(T0, base);
+ GEN_LOAD_REG_TN(T1, index);
+ /* Don't do NOP if destination is zero: we must perform the actual
+ * memory access
+ */
+ switch (opc) {
+ case OPC_LWXC1:
+ op_ldst(lwxc1);
+ GEN_STORE_FTN_FREG(fd, WT0);
+ opn = "lwxc1";
+ break;
+ case OPC_LDXC1:
+ op_ldst(ldxc1);
+ GEN_STORE_FTN_FREG(fd, DT0);
+ opn = "ldxc1";
+ break;
+ case OPC_LUXC1:
+ op_ldst(luxc1);
+ GEN_STORE_FTN_FREG(fd, DT0);
+ opn = "luxc1";
+ break;
+ case OPC_SWXC1:
+ GEN_LOAD_FREG_FTN(WT0, fd);
+ op_ldst(swxc1);
+ opn = "swxc1";
+ break;
+ case OPC_SDXC1:
+ GEN_LOAD_FREG_FTN(DT0, fd);
+ op_ldst(sdxc1);
+ opn = "sdxc1";
+ break;
+ case OPC_SUXC1:
+ GEN_LOAD_FREG_FTN(DT0, fd);
+ op_ldst(suxc1);
+ opn = "suxc1";
+ break;
+ default:
+ MIPS_INVAL("extended float load/store");
+ generate_exception(ctx, EXCP_RI);
+ return;
+ }
+ MIPS_DEBUG("%s %s, %s(%s)", opn, fregnames[fd],regnames[index], regnames[base]);
}
-#endif /* MIPS_USES_FPU */
+static void gen_flt3_arith (DisasContext *ctx, uint32_t opc, int fd,
+ int fr, int fs, int ft)
+{
+ const char *opn = "unk";
+ /* All of those work only on 64bit FPUs. */
+ CHECK_FR(ctx, fd | fr | fs | ft);
+ switch (opc) {
+ case OPC_ALNV_PS:
+ GEN_LOAD_REG_TN(T0, fr);
+ GEN_LOAD_FREG_FTN(DT0, fs);
+ GEN_LOAD_FREG_FTN(DT1, ft);
+ gen_op_float_alnv_ps();
+ GEN_STORE_FTN_FREG(fd, DT2);
+ opn = "alnv.ps";
+ break;
+ case OPC_MADD_S:
+ GEN_LOAD_FREG_FTN(WT0, fs);
+ GEN_LOAD_FREG_FTN(WT1, ft);
+ GEN_LOAD_FREG_FTN(WT2, fr);
+ gen_op_float_muladd_s();
+ GEN_STORE_FTN_FREG(fd, WT2);
+ opn = "madd.s";
+ break;
+ case OPC_MADD_D:
+ generate_exception (ctx, EXCP_RI);
+ opn = "madd.d";
+ break;
+ case OPC_MADD_PS:
+ generate_exception (ctx, EXCP_RI);
+ opn = "madd.ps";
+ break;
+ case OPC_MSUB_S:
+ generate_exception (ctx, EXCP_RI);
+ opn = "msub.s";
+ break;
+ case OPC_MSUB_D:
+ generate_exception (ctx, EXCP_RI);
+ opn = "msub.d";
+ break;
+ case OPC_MSUB_PS:
+ generate_exception (ctx, EXCP_RI);
+ opn = "msub.ps";
+ break;
+ case OPC_NMADD_S:
+ generate_exception (ctx, EXCP_RI);
+ opn = "nmadd.s";
+ break;
+ case OPC_NMADD_D:
+ generate_exception (ctx, EXCP_RI);
+ opn = "nmadd.d";
+ break;
+ case OPC_NMADD_PS:
+ generate_exception (ctx, EXCP_RI);
+ opn = "nmadd.ps";
+ break;
+ case OPC_NMSUB_S:
+ generate_exception (ctx, EXCP_RI);
+ opn = "nmsub.s";
+ break;
+ case OPC_NMSUB_D:
+ generate_exception (ctx, EXCP_RI);
+ opn = "nmsub.d";
+ break;
+ case OPC_NMSUB_PS:
+ generate_exception (ctx, EXCP_RI);
+ opn = "nmsub.ps";
+ break;
+ default:
+ if (loglevel & CPU_LOG_TB_IN_ASM) {
+ fprintf(logfile, "Invalid extended FP arith function: %08x %03x %03x\n",
+ ctx->opcode, ctx->opcode >> 26, ctx->opcode & 0x3F);
+ }
+ generate_exception (ctx, EXCP_RI);
+ return;
+ }
+ MIPS_DEBUG("%s %s, %s, %s, %s", opn, fregnames[fd], fregnames[fr],
+ fregnames[fs], fregnames[ft]);
+}
+
/* ISA extensions (ASEs) */
/* MIPS16 extension to MIPS32 */
/* SmartMIPS extension to MIPS32 */
-#ifdef MIPS_HAS_MIPS64
-/* Coprocessor 3 (FPU) */
+#ifdef TARGET_MIPS64
/* MDMX extension to MIPS64 */
/* MIPS-3D extension to MIPS64 */
#endif
-static void gen_blikely(DisasContext *ctx)
+static void decode_opc (CPUState *env, DisasContext *ctx)
{
- int l1;
- l1 = gen_new_label();
- gen_op_jnz_T2(l1);
- gen_op_save_state(ctx->hflags & ~MIPS_HFLAG_BMASK);
- gen_goto_tb(ctx, 1, ctx->pc + 4);
- gen_set_label(l1);
-}
-
-static void decode_opc (DisasContext *ctx)
-{
int32_t offset;
int rs, rt, rd, sa;
uint32_t op, op1, op2;
@@ -3380,14 +5204,20 @@
/* make sure instructions are on a word boundary */
if (ctx->pc & 0x3) {
+ env->CP0_BadVAddr = ctx->pc;
generate_exception(ctx, EXCP_AdEL);
return;
}
if ((ctx->hflags & MIPS_HFLAG_BMASK) == MIPS_HFLAG_BL) {
+ int l1;
/* Handle blikely not taken case */
- MIPS_DEBUG("blikely condition (" TLSZ ")", ctx->pc + 4);
- gen_blikely(ctx);
+ MIPS_DEBUG("blikely condition (" TARGET_FMT_lx ")", ctx->pc + 4);
+ l1 = gen_new_label();
+ gen_op_jnz_T2(l1);
+ gen_op_save_state(ctx->hflags & ~MIPS_HFLAG_BMASK);
+ gen_goto_tb(ctx, 1, ctx->pc + 4);
+ gen_set_label(l1);
}
op = MASK_OP_MAJOR(ctx->opcode);
rs = (ctx->opcode >> 21) & 0x1f;
@@ -3428,34 +5258,46 @@
case OPC_MTLO: /* Move to HI/LO */
gen_HILO(ctx, op1, rs);
break;
- case OPC_PMON: /* Pmon entry point */
+ case OPC_PMON: /* Pmon entry point, also R4010 selsl */
+#ifdef MIPS_STRICT_STANDARD
+ MIPS_INVAL("PMON / selsl");
+ generate_exception(ctx, EXCP_RI);
+#else
gen_op_pmon(sa);
+#endif
break;
case OPC_SYSCALL:
generate_exception(ctx, EXCP_SYSCALL);
- ctx->bstate = BS_EXCP;
break;
case OPC_BREAK:
generate_exception(ctx, EXCP_BREAK);
break;
- case OPC_SPIM: /* SPIM ? */
+ case OPC_SPIM:
+#ifdef MIPS_STRICT_STANDARD
+ MIPS_INVAL("SPIM");
+ generate_exception(ctx, EXCP_RI);
+#else
/* Implemented as RI exception for now. */
MIPS_INVAL("spim (unofficial)");
generate_exception(ctx, EXCP_RI);
+#endif
break;
case OPC_SYNC:
/* Treat as a noop. */
break;
-#ifdef MIPS_USES_FPU
case OPC_MOVCI:
- gen_op_cp1_enabled();
- gen_movci(ctx, rd, rs, (ctx->opcode >> 18) & 0x7,
- (ctx->opcode >> 16) & 1);
+ if (env->CP0_Config1 & (1 << CP0C1_FP)) {
+ save_cpu_state(ctx, 1);
+ gen_op_cp1_enabled();
+ gen_movci(ctx, rd, rs, (ctx->opcode >> 18) & 0x7,
+ (ctx->opcode >> 16) & 1);
+ } else {
+ generate_exception_err(ctx, EXCP_CpU, 1);
+ }
break;
-#endif
-#ifdef MIPS_HAS_MIPS64
+#ifdef TARGET_MIPS64
/* MIPS64 specific opcodes */
case OPC_DSLL:
case OPC_DSRL ... OPC_DSRA:
@@ -3502,7 +5344,7 @@
}
/* Treat as a noop */
break;
-#ifdef MIPS_HAS_MIPS64
+#ifdef TARGET_MIPS64
case OPC_DCLZ ... OPC_DCLO:
gen_cl(ctx, op1, rd, rs);
break;
@@ -3514,77 +5356,86 @@
}
break;
case OPC_SPECIAL3:
- op1 = MASK_SPECIAL3(ctx->opcode);
- switch (op1) {
- case OPC_EXT:
- case OPC_INS:
+ op1 = MASK_SPECIAL3(ctx->opcode);
+ switch (op1) {
+ case OPC_EXT:
+ case OPC_INS:
+ gen_bitops(ctx, op1, rt, rs, sa, rd);
+ break;
+ case OPC_BSHFL:
+ op2 = MASK_BSHFL(ctx->opcode);
+ switch (op2) {
+ case OPC_WSBH:
+ GEN_LOAD_REG_TN(T1, rt);
+ gen_op_wsbh();
+ break;
+ case OPC_SEB:
+ GEN_LOAD_REG_TN(T1, rt);
+ gen_op_seb();
+ break;
+ case OPC_SEH:
+ GEN_LOAD_REG_TN(T1, rt);
+ gen_op_seh();
+ break;
+ default: /* Invalid */
+ MIPS_INVAL("bshfl");
+ generate_exception(ctx, EXCP_RI);
+ break;
+ }
+ GEN_STORE_TN_REG(rd, T0);
+ break;
+ case OPC_RDHWR:
+ switch (rd) {
+ case 0:
+ save_cpu_state(ctx, 1);
+ gen_op_rdhwr_cpunum();
+ break;
+ case 1:
+ save_cpu_state(ctx, 1);
+ gen_op_rdhwr_synci_step();
+ break;
+ case 2:
+ save_cpu_state(ctx, 1);
+ gen_op_rdhwr_cc();
+ break;
+ case 3:
+ save_cpu_state(ctx, 1);
+ gen_op_rdhwr_ccres();
+ break;
+ case 29:
+#if defined (CONFIG_USER_ONLY)
+ gen_op_tls_value ();
+ break;
+#endif
+ default: /* Invalid */
+ MIPS_INVAL("rdhwr");
+ generate_exception(ctx, EXCP_RI);
+ break;
+ }
+ GEN_STORE_TN_REG(rt, T0);
+ break;
+#ifdef TARGET_MIPS64
+ case OPC_DEXTM ... OPC_DEXT:
+ case OPC_DINSM ... OPC_DINS:
gen_bitops(ctx, op1, rt, rs, sa, rd);
break;
- case OPC_BSHFL:
- op2 = MASK_BSHFL(ctx->opcode);
+ case OPC_DBSHFL:
+ op2 = MASK_DBSHFL(ctx->opcode);
switch (op2) {
- case OPC_WSBH:
+ case OPC_DSBH:
GEN_LOAD_REG_TN(T1, rt);
- gen_op_wsbh();
+ gen_op_dsbh();
break;
- case OPC_SEB:
+ case OPC_DSHD:
GEN_LOAD_REG_TN(T1, rt);
- gen_op_seb();
+ gen_op_dshd();
break;
- case OPC_SEH:
- GEN_LOAD_REG_TN(T1, rt);
- gen_op_seh();
- break;
- default: /* Invalid */
- MIPS_INVAL("bshfl");
- generate_exception(ctx, EXCP_RI);
- break;
- }
- GEN_STORE_TN_REG(rd, T0);
- break;
- case OPC_RDHWR:
- switch (rd) {
- case 0:
- gen_op_rdhwr_cpunum();
- break;
- case 1:
- gen_op_rdhwr_synci_step();
- break;
- case 2:
- gen_op_rdhwr_cc();
- break;
- case 3:
- gen_op_rdhwr_ccres();
- break;
- default: /* Invalid */
- MIPS_INVAL("rdhwr");
- generate_exception(ctx, EXCP_RI);
- break;
- }
- GEN_STORE_TN_REG(rt, T0);
- break;
-#ifdef MIPS_HAS_MIPS64
- case OPC_DEXTM ... OPC_DEXT:
- case OPC_DINSM ... OPC_DINS:
- gen_bitops(ctx, op1, rt, rs, sa, rd);
- break;
- case OPC_DBSHFL:
- op2 = MASK_DBSHFL(ctx->opcode);
- switch (op2) {
- case OPC_DSBH:
- GEN_LOAD_REG_TN(T1, rt);
- gen_op_dsbh();
- break;
- case OPC_DSHD:
- GEN_LOAD_REG_TN(T1, rt);
- gen_op_dshd();
- break;
default: /* Invalid */
MIPS_INVAL("dbshfl");
generate_exception(ctx, EXCP_RI);
break;
- }
- GEN_STORE_TN_REG(rd, T0);
+ }
+ GEN_STORE_TN_REG(rd, T0);
#endif
default: /* Invalid */
MIPS_INVAL("special3");
@@ -3604,7 +5455,7 @@
gen_trap(ctx, op1, rs, -1, imm);
break;
case OPC_SYNCI:
- /* treat as noop */
+ /* treat as noop */
break;
default: /* Invalid */
MIPS_INVAL("REGIMM");
@@ -3613,11 +5464,13 @@
}
break;
case OPC_CP0:
+ save_cpu_state(ctx, 1);
+ gen_op_cp0_enabled();
op1 = MASK_CP0(ctx->opcode);
switch (op1) {
case OPC_MFC0:
case OPC_MTC0:
-#ifdef MIPS_HAS_MIPS64
+#ifdef TARGET_MIPS64
case OPC_DMFC0:
case OPC_DMTC0:
#endif
@@ -3646,9 +5499,15 @@
}
GEN_STORE_TN_REG(rt, T0);
break;
- /* Shadow registers (not implemented). */
case OPC_RDPGPR:
case OPC_WRPGPR:
+ if ((env->CP0_Config0 & (0x7 << CP0C0_AR)) == (1 << CP0C0_AR)) {
+ /* Shadow registers not implemented. */
+ GEN_LOAD_REG_TN(T0, rt);
+ GEN_STORE_TN_REG(rd, T0);
+ } else
+ generate_exception(ctx, EXCP_RI);
+ break;
default:
generate_exception(ctx, EXCP_RI);
break;
@@ -3684,43 +5543,52 @@
case OPC_LDC1:
case OPC_SWC1:
case OPC_SDC1:
-#if defined(MIPS_USES_FPU)
- save_cpu_state(ctx, 1);
- gen_op_cp1_enabled();
- gen_flt_ldst(ctx, op, rt, rs, imm);
-#else
- generate_exception_err(ctx, EXCP_CpU, 1);
-#endif
+ if (env->CP0_Config1 & (1 << CP0C1_FP)) {
+ save_cpu_state(ctx, 1);
+ gen_op_cp1_enabled();
+ gen_flt_ldst(ctx, op, rt, rs, imm);
+ } else {
+ generate_exception_err(ctx, EXCP_CpU, 1);
+ }
break;
case OPC_CP1:
-#if defined(MIPS_USES_FPU)
- save_cpu_state(ctx, 1);
- gen_op_cp1_enabled();
- op1 = MASK_CP1(ctx->opcode);
- switch (op1) {
- case OPC_MFC1:
- case OPC_CFC1:
- case OPC_MTC1:
- case OPC_CTC1:
- gen_cp1(ctx, op1, rt, rd);
- break;
- case OPC_BC1:
- gen_compute_branch1(ctx, MASK_CP1_BCOND(ctx->opcode), imm << 2);
- return;
- case OPC_S_FMT:
- case OPC_D_FMT:
- case OPC_W_FMT:
- case OPC_L_FMT:
- gen_farith(ctx, MASK_CP1_FUNC(ctx->opcode), rt, rd, sa);
- break;
- default:
- generate_exception_err(ctx, EXCP_RI, 1);
- break;
+ if (env->CP0_Config1 & (1 << CP0C1_FP)) {
+ save_cpu_state(ctx, 1);
+ gen_op_cp1_enabled();
+ op1 = MASK_CP1(ctx->opcode);
+ switch (op1) {
+ case OPC_MFC1:
+ case OPC_CFC1:
+ case OPC_MTC1:
+ case OPC_CTC1:
+#ifdef TARGET_MIPS64
+ case OPC_DMFC1:
+ case OPC_DMTC1:
+#endif
+ case OPC_MFHC1:
+ case OPC_MTHC1:
+ gen_cp1(ctx, op1, rt, rd);
+ break;
+ case OPC_BC1:
+ gen_compute_branch1(ctx, MASK_BC1(ctx->opcode),
+ (rt >> 2) & 0x7, imm << 2);
+ return;
+ case OPC_S_FMT:
+ case OPC_D_FMT:
+ case OPC_W_FMT:
+ case OPC_L_FMT:
+ case OPC_PS_FMT:
+ gen_farith(ctx, MASK_CP1_FUNC(ctx->opcode), rt, rd, sa,
+ (imm >> 8) & 0x7);
+ break;
+ default:
+ generate_exception (ctx, EXCP_RI);
+ break;
+ }
+ } else {
+ generate_exception_err(ctx, EXCP_CpU, 1);
}
-#else
- generate_exception_err(ctx, EXCP_CpU, 1);
-#endif
break;
/* COP2. */
@@ -3733,20 +5601,48 @@
generate_exception_err(ctx, EXCP_CpU, 2);
break;
-#ifdef MIPS_USES_FPU
case OPC_CP3:
- gen_op_cp1_enabled();
- op1 = MASK_CP3(ctx->opcode);
- switch (op1) {
- /* Not implemented */
- default:
- generate_exception_err(ctx, EXCP_RI, 1);
- break;
+ if (env->CP0_Config1 & (1 << CP0C1_FP)) {
+ save_cpu_state(ctx, 1);
+ gen_op_cp1_enabled();
+ op1 = MASK_CP3(ctx->opcode);
+ switch (op1) {
+ case OPC_LWXC1:
+ case OPC_LDXC1:
+ case OPC_LUXC1:
+ case OPC_SWXC1:
+ case OPC_SDXC1:
+ case OPC_SUXC1:
+ gen_flt3_ldst(ctx, op1, sa, rs, rt);
+ break;
+ case OPC_PREFX:
+ /* treat as noop */
+ break;
+ case OPC_ALNV_PS:
+ case OPC_MADD_S:
+ case OPC_MADD_D:
+ case OPC_MADD_PS:
+ case OPC_MSUB_S:
+ case OPC_MSUB_D:
+ case OPC_MSUB_PS:
+ case OPC_NMADD_S:
+ case OPC_NMADD_D:
+ case OPC_NMADD_PS:
+ case OPC_NMSUB_S:
+ case OPC_NMSUB_D:
+ case OPC_NMSUB_PS:
+ gen_flt3_arith(ctx, op1, sa, rs, rd, rt);
+ break;
+ default:
+ generate_exception (ctx, EXCP_RI);
+ break;
+ }
+ } else {
+ generate_exception_err(ctx, EXCP_CpU, 1);
}
break;
-#endif
-#ifdef MIPS_HAS_MIPS64
+#ifdef TARGET_MIPS64
/* MIPS64 opcodes */
case OPC_LWU:
case OPC_LDL ... OPC_LDR:
@@ -3775,12 +5671,12 @@
break;
}
if (ctx->hflags & MIPS_HFLAG_BMASK) {
- int hflags = ctx->hflags;
+ int hflags = ctx->hflags & MIPS_HFLAG_BMASK;
/* Branches completion */
ctx->hflags &= ~MIPS_HFLAG_BMASK;
ctx->bstate = BS_BRANCH;
save_cpu_state(ctx, 0);
- switch (hflags & MIPS_HFLAG_BMASK) {
+ switch (hflags) {
case MIPS_HFLAG_B:
/* unconditional branch */
MIPS_DEBUG("unconditional branch");
@@ -3807,6 +5703,8 @@
/* unconditional branch to register */
MIPS_DEBUG("branch to register");
gen_op_breg();
+ gen_op_reset_T0();
+ gen_op_exit_tb();
break;
default:
MIPS_DEBUG("unknown branch");
@@ -3815,8 +5713,9 @@
}
}
-int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
- int search_pc)
+static inline int
+gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
+ int search_pc)
{
DisasContext ctx, *ctxp = &ctx;
target_ulong pc_start;
@@ -3838,16 +5737,18 @@
/* Restore delay slot state from the tb context. */
ctx.hflags = tb->flags;
ctx.saved_hflags = ctx.hflags;
- if (ctx.hflags & MIPS_HFLAG_BR) {
+ switch (ctx.hflags & MIPS_HFLAG_BMASK) {
+ case MIPS_HFLAG_BR:
gen_op_restore_breg_target();
- } else if (ctx.hflags & MIPS_HFLAG_B) {
+ break;
+ case MIPS_HFLAG_B:
ctx.btarget = env->btarget;
- } else if (ctx.hflags & MIPS_HFLAG_BMASK) {
- /* If we are in the delay slot of a conditional branch,
- * restore the branch condition from env->bcond to T2
- */
+ break;
+ case MIPS_HFLAG_BC:
+ case MIPS_HFLAG_BL:
ctx.btarget = env->btarget;
gen_op_restore_bcond();
+ break;
}
#if defined(CONFIG_USER_ONLY)
ctx.mem_idx = 0;
@@ -3891,7 +5792,7 @@
gen_opc_instr_start[lj] = 1;
}
ctx.opcode = ldl_code(ctx.pc);
- decode_opc(&ctx);
+ decode_opc(env, &ctx);
ctx.pc += 4;
if (env->singlestep_enabled)
@@ -3907,15 +5808,25 @@
if (env->singlestep_enabled) {
save_cpu_state(ctxp, ctx.bstate == BS_NONE);
gen_op_debug();
- goto done_generating;
+ } else {
+ switch (ctx.bstate) {
+ case BS_STOP:
+ gen_op_interrupt_restart();
+ /* Fall through. */
+ case BS_NONE:
+ save_cpu_state(ctxp, 0);
+ gen_goto_tb(&ctx, 0, ctx.pc);
+ break;
+ case BS_EXCP:
+ gen_op_interrupt_restart();
+ gen_op_reset_T0();
+ gen_op_exit_tb();
+ break;
+ case BS_BRANCH:
+ default:
+ break;
+ }
}
- else if (ctx.bstate != BS_BRANCH && ctx.bstate != BS_EXCP) {
- save_cpu_state(ctxp, 0);
- gen_goto_tb(&ctx, 0, ctx.pc);
- }
- gen_op_reset_T0();
- /* Generate the return instruction */
- gen_op_exit_tb();
done_generating:
*gen_opc_ptr = INDEX_op_end;
if (search_pc) {
@@ -3934,7 +5845,7 @@
#endif
if (loglevel & CPU_LOG_TB_IN_ASM) {
fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
- target_disas(logfile, pc_start, ctx.pc - pc_start, 0);
+ target_disas(logfile, pc_start, ctx.pc - pc_start, 0);
fprintf(logfile, "\n");
}
if (loglevel & CPU_LOG_TB_OP) {
@@ -3960,28 +5871,38 @@
return gen_intermediate_code_internal(env, tb, 1);
}
-#ifdef MIPS_USES_FPU
-
void fpu_dump_state(CPUState *env, FILE *f,
int (*fpu_fprintf)(FILE *f, const char *fmt, ...),
int flags)
{
int i;
+ int is_fpu64 = !!(env->CP0_Status & (1 << CP0St_FR));
-# define printfpr(fp) do { \
- fpu_fprintf(f, "w:%08x d:%08lx%08lx fd:%g fs:%g\n", \
- (fp)->w[FP_ENDIAN_IDX], (fp)->w[0], (fp)->w[1], (fp)->fd, (fp)->fs[FP_ENDIAN_IDX]); \
+#define printfpr(fp) \
+ do { \
+ if (is_fpu64) \
+ fpu_fprintf(f, "w:%08x d:%016lx fd:%13g fs:%13g psu: %13g\n", \
+ (fp)->w[FP_ENDIAN_IDX], (fp)->d, (fp)->fd, \
+ (fp)->fs[FP_ENDIAN_IDX], (fp)->fs[!FP_ENDIAN_IDX]); \
+ else { \
+ fpr_t tmp; \
+ tmp.w[FP_ENDIAN_IDX] = (fp)->w[FP_ENDIAN_IDX]; \
+ tmp.w[!FP_ENDIAN_IDX] = ((fp) + 1)->w[FP_ENDIAN_IDX]; \
+ fpu_fprintf(f, "w:%08x d:%016lx fd:%13g fs:%13g psu:%13g\n", \
+ tmp.w[FP_ENDIAN_IDX], tmp.d, tmp.fd, \
+ tmp.fs[FP_ENDIAN_IDX], tmp.fs[!FP_ENDIAN_IDX]); \
+ } \
} while(0)
- fpu_fprintf(f, "CP1 FCR0 0x%08x FCR31 0x%08x SR.FR %d\n",
- env->fcr0, env->fcr31,
- (env->CP0_Status & (1 << CP0St_FR)) != 0);
+
+ fpu_fprintf(f, "CP1 FCR0 0x%08x FCR31 0x%08x SR.FR %d fp_status 0x%08x(0x%02x)\n",
+ env->fcr0, env->fcr31, is_fpu64, env->fp_status, get_float_exception_flags(&env->fp_status));
fpu_fprintf(f, "FT0: "); printfpr(&env->ft0);
fpu_fprintf(f, "FT1: "); printfpr(&env->ft1);
fpu_fprintf(f, "FT2: "); printfpr(&env->ft2);
- for(i = 0; i < 32; i += 2) {
- fpu_fprintf(f, "%s: ", fregnames[i]);
- printfpr(FPR(env, i));
+ for (i = 0; i < 32; (is_fpu64) ? i++ : (i += 2)) {
+ fpu_fprintf(f, "%3s: ", fregnames[i]);
+ printfpr(&env->fpr[i]);
}
#undef printfpr
@@ -3990,15 +5911,13 @@
void dump_fpu (CPUState *env)
{
if (loglevel) {
- fprintf(logfile, "pc=0x" TLSZ " HI=0x" TLSZ " LO=0x" TLSZ " ds %04x " TLSZ " %d\n",
+ fprintf(logfile, "pc=0x" TARGET_FMT_lx " HI=0x" TARGET_FMT_lx " LO=0x" TARGET_FMT_lx " ds %04x " TARGET_FMT_lx " %d\n",
env->PC, env->HI, env->LO, env->hflags, env->btarget, env->bcond);
fpu_dump_state(env, logfile, fprintf, 0);
}
}
-#endif /* MIPS_USES_FPU */
-
-#if defined(MIPS_HAS_MIPS64) && defined(MIPS_DEBUG_SIGN_EXTENSIONS)
+#if defined(TARGET_MIPS64) && defined(MIPS_DEBUG_SIGN_EXTENSIONS)
/* Debug help: The architecture requires 32bit code to maintain proper
sign-extened values on 64bit machines. */
@@ -4011,23 +5930,23 @@
int i;
if (!SIGN_EXT_P(env->PC))
- cpu_fprintf(f, "BROKEN: pc=0x" TLSZ "\n", env->PC);
+ cpu_fprintf(f, "BROKEN: pc=0x" TARGET_FMT_lx "\n", env->PC);
if (!SIGN_EXT_P(env->HI))
- cpu_fprintf(f, "BROKEN: HI=0x" TLSZ "\n", env->HI);
+ cpu_fprintf(f, "BROKEN: HI=0x" TARGET_FMT_lx "\n", env->HI);
if (!SIGN_EXT_P(env->LO))
- cpu_fprintf(f, "BROKEN: LO=0x" TLSZ "\n", env->LO);
+ cpu_fprintf(f, "BROKEN: LO=0x" TARGET_FMT_lx "\n", env->LO);
if (!SIGN_EXT_P(env->btarget))
- cpu_fprintf(f, "BROKEN: btarget=0x" TLSZ "\n", env->btarget);
+ cpu_fprintf(f, "BROKEN: btarget=0x" TARGET_FMT_lx "\n", env->btarget);
for (i = 0; i < 32; i++) {
if (!SIGN_EXT_P(env->gpr[i]))
- cpu_fprintf(f, "BROKEN: %s=0x" TLSZ "\n", regnames[i], env->gpr[i]);
+ cpu_fprintf(f, "BROKEN: %s=0x" TARGET_FMT_lx "\n", regnames[i], env->gpr[i]);
}
if (!SIGN_EXT_P(env->CP0_EPC))
- cpu_fprintf(f, "BROKEN: EPC=0x" TLSZ "\n", env->CP0_EPC);
+ cpu_fprintf(f, "BROKEN: EPC=0x" TARGET_FMT_lx "\n", env->CP0_EPC);
if (!SIGN_EXT_P(env->CP0_LLAddr))
- cpu_fprintf(f, "BROKEN: LLAddr=0x" TLSZ "\n", env->CP0_LLAddr);
+ cpu_fprintf(f, "BROKEN: LLAddr=0x" TARGET_FMT_lx "\n", env->CP0_LLAddr);
}
#endif
@@ -4038,33 +5957,25 @@
uint32_t c0_status;
int i;
- cpu_fprintf(f, "pc=0x" TLSZ " HI=0x" TLSZ " LO=0x" TLSZ " ds %04x " TLSZ " %d\n",
+ cpu_fprintf(f, "pc=0x" TARGET_FMT_lx " HI=0x" TARGET_FMT_lx " LO=0x" TARGET_FMT_lx " ds %04x " TARGET_FMT_lx " %d\n",
env->PC, env->HI, env->LO, env->hflags, env->btarget, env->bcond);
for (i = 0; i < 32; i++) {
if ((i & 3) == 0)
cpu_fprintf(f, "GPR%02d:", i);
- cpu_fprintf(f, " %s " TLSZ, regnames[i], env->gpr[i]);
+ cpu_fprintf(f, " %s " TARGET_FMT_lx, regnames[i], env->gpr[i]);
if ((i & 3) == 3)
cpu_fprintf(f, "\n");
}
c0_status = env->CP0_Status;
- if (env->hflags & MIPS_HFLAG_UM)
- c0_status |= (1 << CP0St_UM);
- if (env->hflags & MIPS_HFLAG_ERL)
- c0_status |= (1 << CP0St_ERL);
- if (env->hflags & MIPS_HFLAG_EXL)
- c0_status |= (1 << CP0St_EXL);
- cpu_fprintf(f, "CP0 Status 0x%08x Cause 0x%08x EPC 0x" TLSZ "\n",
+ cpu_fprintf(f, "CP0 Status 0x%08x Cause 0x%08x EPC 0x" TARGET_FMT_lx "\n",
c0_status, env->CP0_Cause, env->CP0_EPC);
- cpu_fprintf(f, " Config0 0x%08x Config1 0x%08x LLAddr 0x" TLSZ "\n",
+ cpu_fprintf(f, " Config0 0x%08x Config1 0x%08x LLAddr 0x" TARGET_FMT_lx "\n",
env->CP0_Config0, env->CP0_Config1, env->CP0_LLAddr);
-#ifdef MIPS_USES_FPU
if (c0_status & (1 << CP0St_CU1))
fpu_dump_state(env, f, cpu_fprintf, flags);
-#endif
-#if defined(MIPS_HAS_MIPS64) && defined(MIPS_DEBUG_SIGN_EXTENSIONS)
+#if defined(TARGET_MIPS64) && defined(MIPS_DEBUG_SIGN_EXTENSIONS)
cpu_mips_check_sign_extensions(env, f, cpu_fprintf, flags);
#endif
}
@@ -4097,34 +6008,25 @@
} else {
env->CP0_ErrorEPC = env->PC;
}
+ env->hflags = 0;
env->PC = (int32_t)0xBFC00000;
-#if defined (MIPS_USES_R4K_TLB)
- env->CP0_random = MIPS_TLB_NB - 1;
- env->tlb_in_use = MIPS_TLB_NB;
-#endif
env->CP0_Wired = 0;
/* SMP not implemented */
- env->CP0_EBase = (int32_t)0x80000000;
- env->CP0_Config0 = MIPS_CONFIG0;
- env->CP0_Config1 = MIPS_CONFIG1;
- env->CP0_Config2 = MIPS_CONFIG2;
- env->CP0_Config3 = MIPS_CONFIG3;
+ env->CP0_EBase = 0x80000000;
env->CP0_Status = (1 << CP0St_BEV) | (1 << CP0St_ERL);
+ /* vectored interrupts not implemented, timer on int 7,
+ no performance counters. */
+ env->CP0_IntCtl = 0xe0000000;
env->CP0_WatchLo = 0;
- env->hflags = MIPS_HFLAG_ERL;
+ env->CP0_WatchHi = 0;
/* Count register increments in debug mode, EJTAG version 1 */
env->CP0_Debug = (1 << CP0DB_CNT) | (0x1 << CP0DB_VER);
- env->CP0_PRid = MIPS_CPU;
#endif
env->exception_index = EXCP_NONE;
#if defined(CONFIG_USER_ONLY)
env->hflags |= MIPS_HFLAG_UM;
env->user_mode_only = 1;
#endif
-#ifdef MIPS_USES_FPU
- env->fcr0 = MIPS_FCR0;
-#endif
- /* XXX some guesswork here, values are CPU specific */
- env->SYNCI_Step = 16;
- env->CCRes = 2;
}
+
+#include "translate_init.c"
Added: trunk/src/host/qemu-neo1973/target-mips/translate_init.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-mips/translate_init.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/target-mips/translate_init.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,207 @@
+/*
+ * MIPS emulation for qemu: CPU initialisation routines.
+ *
+ * Copyright (c) 2004-2005 Jocelyn Mayer
+ * Copyright (c) 2007 Herve Poussineau
+ *
+ * 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
+ */
+
+/* CPU / CPU family specific config register values. */
+
+/* Have config1, is MIPS32R1, uses TLB, no virtual icache,
+ uncached coherency */
+#define MIPS_CONFIG0 \
+ ((1 << CP0C0_M) | (0x0 << CP0C0_K23) | (0x0 << CP0C0_KU) | \
+ (0x0 << CP0C0_AT) | (0x0 << CP0C0_AR) | (0x1 << CP0C0_MT) | \
+ (0x2 << CP0C0_K0))
+
+/* Have config2, 64 sets Icache, 16 bytes Icache line,
+ 2-way Icache, 64 sets Dcache, 16 bytes Dcache line, 2-way Dcache,
+ no coprocessor2 attached, no MDMX support attached,
+ no performance counters, watch registers present,
+ no code compression, EJTAG present, no FPU */
+#define MIPS_CONFIG1 \
+((1 << CP0C1_M) | \
+ (0x0 << CP0C1_IS) | (0x3 << CP0C1_IL) | (0x1 << CP0C1_IA) | \
+ (0x0 << CP0C1_DS) | (0x3 << CP0C1_DL) | (0x1 << CP0C1_DA) | \
+ (0 << CP0C1_C2) | (0 << CP0C1_MD) | (0 << CP0C1_PC) | \
+ (1 << CP0C1_WR) | (0 << CP0C1_CA) | (1 << CP0C1_EP) | \
+ (0 << CP0C1_FP))
+
+/* Have config3, no tertiary/secondary caches implemented */
+#define MIPS_CONFIG2 \
+((1 << CP0C2_M))
+
+/* No config4, no DSP ASE, no large physaddr,
+ no external interrupt controller, no vectored interupts,
+ no 1kb pages, no MT ASE, no SmartMIPS ASE, no trace logic */
+#define MIPS_CONFIG3 \
+((0 << CP0C3_M) | (0 << CP0C3_DSPP) | (0 << CP0C3_LPA) | \
+ (0 << CP0C3_VEIC) | (0 << CP0C3_VInt) | (0 << CP0C3_SP) | \
+ (0 << CP0C3_MT) | (0 << CP0C3_SM) | (0 << CP0C3_TL))
+
+/* Define a implementation number of 1.
+ Define a major version 1, minor version 0. */
+#define MIPS_FCR0 ((0 << FCR0_S) | (0x1 << FCR0_PRID) | (0x10 << FCR0_REV))
+
+
+struct mips_def_t {
+ const unsigned char *name;
+ int32_t CP0_PRid;
+ int32_t CP0_Config0;
+ int32_t CP0_Config1;
+ int32_t CP0_Config2;
+ int32_t CP0_Config3;
+ int32_t CP0_Config6;
+ int32_t CP0_Config7;
+ int32_t SYNCI_Step;
+ int32_t CCRes;
+ int32_t Status_rw_bitmask;
+ int32_t CP1_fcr0;
+};
+
+/*****************************************************************************/
+/* MIPS CPU definitions */
+static mips_def_t mips_defs[] =
+{
+#ifndef TARGET_MIPS64
+ {
+ .name = "4Kc",
+ .CP0_PRid = 0x00018000,
+ .CP0_Config0 = MIPS_CONFIG0,
+ .CP0_Config1 = MIPS_CONFIG1 | (15 << CP0C1_MMU),
+ .CP0_Config2 = MIPS_CONFIG2,
+ .CP0_Config3 = MIPS_CONFIG3,
+ .SYNCI_Step = 32,
+ .CCRes = 2,
+ .Status_rw_bitmask = 0x3278FF17,
+ },
+ {
+ .name = "4KEcR1",
+ .CP0_PRid = 0x00018400,
+ .CP0_Config0 = MIPS_CONFIG0,
+ .CP0_Config1 = MIPS_CONFIG1 | (15 << CP0C1_MMU),
+ .CP0_Config2 = MIPS_CONFIG2,
+ .CP0_Config3 = MIPS_CONFIG3,
+ .SYNCI_Step = 32,
+ .CCRes = 2,
+ },
+ {
+ .name = "4KEc",
+ .CP0_PRid = 0x00019000,
+ .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR),
+ .CP0_Config1 = MIPS_CONFIG1 | (15 << CP0C1_MMU),
+ .CP0_Config2 = MIPS_CONFIG2,
+ .CP0_Config3 = MIPS_CONFIG3,
+ .SYNCI_Step = 32,
+ .CCRes = 2,
+ .Status_rw_bitmask = 0x3278FF17,
+ },
+ {
+ .name = "24Kc",
+ .CP0_PRid = 0x00019300,
+ .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR),
+ .CP0_Config1 = MIPS_CONFIG1 | (15 << CP0C1_MMU),
+ .CP0_Config2 = MIPS_CONFIG2,
+ .CP0_Config3 = MIPS_CONFIG3,
+ .SYNCI_Step = 32,
+ .CCRes = 2,
+ .Status_rw_bitmask = 0x3278FF17,
+ },
+ {
+ .name = "24Kf",
+ .CP0_PRid = 0x00019300,
+ .CP0_Config0 = MIPS_CONFIG0 | (0x1 << CP0C0_AR),
+ .CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (15 << CP0C1_MMU),
+ .CP0_Config2 = MIPS_CONFIG2,
+ .CP0_Config3 = MIPS_CONFIG3,
+ .SYNCI_Step = 32,
+ .CCRes = 2,
+ .Status_rw_bitmask = 0x3678FF17,
+ .CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) |
+ (1 << FCR0_D) | (1 << FCR0_S) | (0x93 << FCR0_PRID),
+ },
+#else
+ {
+ .name = "R4000",
+ .CP0_PRid = 0x00000400,
+ .CP0_Config0 = MIPS_CONFIG0 | (0x2 << CP0C0_AT),
+ .CP0_Config1 = MIPS_CONFIG1 | (1 << CP0C1_FP) | (47 << CP0C1_MMU),
+ .CP0_Config2 = MIPS_CONFIG2,
+ .CP0_Config3 = MIPS_CONFIG3,
+ .SYNCI_Step = 16,
+ .CCRes = 2,
+ .Status_rw_bitmask = 0x3678FFFF,
+ .CP1_fcr0 = (1 << FCR0_F64) | (1 << FCR0_L) | (1 << FCR0_W) |
+ (1 << FCR0_D) | (1 << FCR0_S) |
+ (0x4 << FCR0_PRID) | (0x0 << FCR0_REV),
+ },
+#endif
+};
+
+int mips_find_by_name (const unsigned char *name, mips_def_t **def)
+{
+ int i, ret;
+
+ ret = -1;
+ *def = NULL;
+ for (i = 0; i < sizeof(mips_defs) / sizeof(mips_defs[0]); i++) {
+ if (strcasecmp(name, mips_defs[i].name) == 0) {
+ *def = &mips_defs[i];
+ ret = 0;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+void mips_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
+{
+ int i;
+
+ for (i = 0; i < sizeof(mips_defs) / sizeof(mips_defs[0]); i++) {
+ (*cpu_fprintf)(f, "MIPS '%s'\n",
+ mips_defs[i].name);
+ }
+}
+
+int cpu_mips_register (CPUMIPSState *env, mips_def_t *def)
+{
+ if (!def)
+ cpu_abort(env, "Unable to find MIPS CPU definition\n");
+ env->CP0_PRid = def->CP0_PRid;
+#ifdef TARGET_WORDS_BIGENDIAN
+ env->CP0_Config0 = def->CP0_Config0 | (1 << CP0C0_BE);
+#else
+ env->CP0_Config0 = def->CP0_Config0;
+#endif
+ env->CP0_Config1 = def->CP0_Config1;
+ env->CP0_Config2 = def->CP0_Config2;
+ env->CP0_Config3 = def->CP0_Config3;
+ env->CP0_Config6 = def->CP0_Config6;
+ env->CP0_Config7 = def->CP0_Config7;
+ env->SYNCI_Step = def->SYNCI_Step;
+ env->CCRes = def->CCRes;
+ env->Status_rw_bitmask = def->Status_rw_bitmask;
+ env->fcr0 = def->CP1_fcr0;
+#if defined (MIPS_USES_R4K_TLB)
+ env->nb_tlb = 1 + ((def->CP0_Config1 >> CP0C1_MMU) & 63);
+ env->CP0_Random = env->nb_tlb - 1;
+ env->tlb_in_use = env->nb_tlb;
+#endif
+ return 0;
+}
Added: trunk/src/host/qemu-neo1973/target-ppc/STATUS
===================================================================
--- trunk/src/host/qemu-neo1973/target-ppc/STATUS 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/target-ppc/STATUS 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,105 @@
+PowerPC emulation status.
+The goal of this file is to provide a reference status to avoid regressions.
+
+===============================================================================
+PowerPC core emulation status
+
+PowerPC CPU known to work (ie booting at least Linux 2.4):
+* main stream PowerPC cores
+- PowerPC 603 & derivatives
+- PowerPC 604 & derivatives
+- PowerPC 740 & derivatives
+- PowerPC 750 & derivatives
+- PowerPC 405
+
+PowerPC that should work but are not supported by standard Linux kernel
+(then remain mostly untested)
+- PowerPC 745
+- PowerPC 755
+
+Work in progress:
+* embedded PowerPC cores
+- BookE PowerPC
+- e500 core (Freescale PowerQUICC)
+* main stream PowerPC cores
+- PowerPC 601
+- PowerPC 602
+
+TODO:
+* embedded PowerPC cores
+- PowerPC 401
+- PowerPC 403
+- PowerPC 440
+- PowerPC 460
+* main stream PowerPC cores
+- PowerPC 7400 (aka G4)
+- PowerPC 7410
+- PowerPC 7450
+- PowerPC 7455
+- PowerPC 7457
+- PowerPC 7457A
+* original POWER
+- POWER
+- POWER2
+* 64 bits PowerPC cores
+- PowerPC 620
+- PowerPC 630 (aka POWER3)
+- PowerPC 631 (aka POWER3+)
+- POWER4
+- POWER4+
+- POWER5
+- POWER5+
+- PowerPC 970
+* RS64 series
+- RS64
+- RS64-II
+- RS64-III
+- RS64-IV
+
+===============================================================================
+PowerPC microcontrollers emulation status
+
+Implemementation should be sufficient to boot Linux:
+- PowerPC 405CR
+- PowerPC 405EP
+
+TODO:
+- More PowerPC 40x microcontrollers emulation
+- PowerQUICC microcontrollers emulation
+
+===============================================================================
+PowerPC based platforms emulation status
+
+* PREP platform (RS/6000 7043...) - TO BE CHECKED (broken)
+- Gentoo Linux live CDROM 1.4
+- Debian Linux 3.0
+- Mandrake Linux 9
+
+* heathrow PowerMac platform (beige PowerMac) - TO BE CHECKED (broken)
+- Gentoo Linux live CDROM 1.4
+- Debian Linux 3.0
+- Mandrake Linux 9
+
+* mac99 platform (white and blue PowerMac, ...)
+- Gentoo Linux live CDROM 1.4 - boots, compiles linux kernel
+- Debian Linux woody - boots from CDROM and HDD
+- Mandrake Linux 9 - boots from CDROM, freezes during install
+- Knoppix 2003-07-13_4 boots from CDROM, pb with X configuration
+ distribution bug: X runs with a properly hand-coded configuration.
+- rock Linux 2.0 runs from CDROM
+
+* Linux 2.6 support seems deadly broken (used to boot...).
+
+* PowerPC 405EP reference boards:
+- can boot Linux 2.4 & 2.6.
+ Need to provide a flash image ready to boot for reproductible tests.
+
+TODO:
+- MCA based RS/6000 emulation
+- CHRP emulation (not PowerMac)
+- PPAR emulation
+- ePPAR emulation
+- misc PowerPC reference boards emulation
+
+===============================================================================
+(to be completed)
Modified: trunk/src/host/qemu-neo1973/target-ppc/cpu.h
===================================================================
--- trunk/src/host/qemu-neo1973/target-ppc/cpu.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/target-ppc/cpu.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -1,7 +1,7 @@
/*
* PowerPC emulation cpu definitions for qemu.
*
- * Copyright (c) 2003-2005 Jocelyn Mayer
+ * Copyright (c) 2003-2007 Jocelyn Mayer
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -21,18 +21,57 @@
#define __CPU_PPC_H__
#include "config.h"
+#include <inttypes.h>
+#if !defined(TARGET_PPCEMB)
+#if defined(TARGET_PPC64) || (HOST_LONG_BITS >= 64)
+/* When using 64 bits temporary registers,
+ * we can use 64 bits GPR with no extra cost
+ */
+#define TARGET_PPCEMB
+#endif
+#endif
+
+#if defined (TARGET_PPC64)
+typedef uint64_t ppc_gpr_t;
+#define TARGET_LONG_BITS 64
+#define TARGET_GPR_BITS 64
+#define REGX "%016" PRIx64
+#define TARGET_PAGE_BITS 12
+#elif defined(TARGET_PPCEMB)
+/* e500v2 have 36 bits physical address space */
+#define TARGET_PHYS_ADDR_BITS 64
+/* GPR are 64 bits: used by vector extension */
+typedef uint64_t ppc_gpr_t;
#define TARGET_LONG_BITS 32
+#define TARGET_GPR_BITS 64
+#define REGX "%016" PRIx64
+/* Pages can be 1 kB small */
+#define TARGET_PAGE_BITS 10
+#else
+typedef uint32_t ppc_gpr_t;
+#define TARGET_LONG_BITS 32
+#define TARGET_GPR_BITS 32
+#define REGX "%08" PRIx32
+#define TARGET_PAGE_BITS 12
+#endif
#include "cpu-defs.h"
+#define ADDRX TARGET_FMT_lx
+#define PADDRX TARGET_FMT_plx
+
#include <setjmp.h>
#include "softfloat.h"
#define TARGET_HAS_ICE 1
-#define ELF_MACHINE EM_PPC
+#if defined (TARGET_PPC64)
+#define ELF_MACHINE EM_PPC64
+#else
+#define ELF_MACHINE EM_PPC
+#endif
/* XXX: this should be tunable: PowerPC 601 & 64 bits PowerPC
* have different cache line sizes
@@ -42,6 +81,7 @@
/* XXX: put this in a common place */
#define likely(x) __builtin_expect(!!(x), 1)
+#define unlikely(x) __builtin_expect(!!(x), 0)
/*****************************************************************************/
/* PVR definitions for most known PowerPC */
@@ -54,72 +94,155 @@
CPU_PPC_401E2 = 0x00250000,
CPU_PPC_401F2 = 0x00260000,
CPU_PPC_401G2 = 0x00270000,
- CPU_PPC_IOP480 = 0x40100000,
+#define CPU_PPC_401 CPU_PPC_401G2
+ CPU_PPC_IOP480 = 0x40100000, /* 401B2 ? */
+ CPU_PPC_COBRA = 0x10100000, /* IBM Processor for Network Resources */
/* PowerPC 403 cores */
- CPU_PPC_403GA = 0x00200000,
+ CPU_PPC_403GA = 0x00200011,
CPU_PPC_403GB = 0x00200100,
CPU_PPC_403GC = 0x00200200,
CPU_PPC_403GCX = 0x00201400,
+#define CPU_PPC_403 CPU_PPC_403GCX
/* PowerPC 405 cores */
- CPU_PPC_405 = 0x40110000,
- CPU_PPC_405EP = 0x51210000,
- CPU_PPC_405GPR = 0x50910000,
+ CPU_PPC_405CR = 0x40110145,
+#define CPU_PPC_405GP CPU_PPC_405CR
+ CPU_PPC_405EP = 0x51210950,
+ CPU_PPC_405GPR = 0x50910951,
CPU_PPC_405D2 = 0x20010000,
CPU_PPC_405D4 = 0x41810000,
- CPU_PPC_NPE405H = 0x41410000,
- CPU_PPC_NPE405L = 0x41610000,
+#define CPU_PPC_405 CPU_PPC_405D4
+ CPU_PPC_NPE405H = 0x414100C0,
+ CPU_PPC_NPE405H2 = 0x41410140,
+ CPU_PPC_NPE405L = 0x416100C0,
+ /* XXX: missing 405LP, LC77700 */
+ /* IBM STBxxx (PowerPC 401/403/405 core based microcontrollers) */
#if 0
- CPU_PPC_STB02 = xxx,
+ CPU_PPC_STB01000 = xxx,
#endif
+#if 0
+ CPU_PPC_STB01010 = xxx,
+#endif
+#if 0
+ CPU_PPC_STB0210 = xxx,
+#endif
CPU_PPC_STB03 = 0x40310000,
#if 0
- CPU_PPC_STB04 = xxx,
+ CPU_PPC_STB043 = xxx,
#endif
- CPU_PPC_STB25 = 0x51510000,
#if 0
+ CPU_PPC_STB045 = xxx,
+#endif
+ CPU_PPC_STB25 = 0x51510950,
+#if 0
CPU_PPC_STB130 = xxx,
#endif
+ /* Xilinx cores */
+ CPU_PPC_X2VP4 = 0x20010820,
+#define CPU_PPC_X2VP7 CPU_PPC_X2VP4
+ CPU_PPC_X2VP20 = 0x20010860,
+#define CPU_PPC_X2VP50 CPU_PPC_X2VP20
/* PowerPC 440 cores */
- CPU_PPC_440EP = 0x42220000,
- CPU_PPC_440GP = 0x40120400,
- CPU_PPC_440GX = 0x51B20000,
- /* PowerPC MPC 8xx cores */
- CPU_PPC_8540 = 0x80200000,
+ CPU_PPC_440EP = 0x422218D3,
+#define CPU_PPC_440GR CPU_PPC_440EP
+ CPU_PPC_440GP = 0x40120481,
+ CPU_PPC_440GX = 0x51B21850,
+ CPU_PPC_440GXc = 0x51B21892,
+ CPU_PPC_440GXf = 0x51B21894,
+ CPU_PPC_440SP = 0x53221850,
+ CPU_PPC_440SP2 = 0x53221891,
+ CPU_PPC_440SPE = 0x53421890,
+ /* XXX: missing 440GRX */
+ /* PowerPC 460 cores - TODO */
+ /* PowerPC MPC 5xx cores */
+ CPU_PPC_5xx = 0x00020020,
+ /* PowerPC MPC 8xx cores (aka PowerQUICC) */
CPU_PPC_8xx = 0x00500000,
- CPU_PPC_8240 = 0x00810100,
- CPU_PPC_8245 = 0x00811014,
+ /* PowerPC MPC 8xxx cores (aka PowerQUICC-II) */
+ CPU_PPC_82xx_HIP3 = 0x00810101,
+ CPU_PPC_82xx_HIP4 = 0x80811014,
+ CPU_PPC_827x = 0x80822013,
+ /* eCores */
+ CPU_PPC_e200 = 0x81120000,
+ CPU_PPC_e500v110 = 0x80200010,
+ CPU_PPC_e500v120 = 0x80200020,
+ CPU_PPC_e500v210 = 0x80210010,
+ CPU_PPC_e500v220 = 0x80210020,
+#define CPU_PPC_e500 CPU_PPC_e500v220
+ CPU_PPC_e600 = 0x80040010,
/* PowerPC 6xx cores */
- CPU_PPC_601 = 0x00010000,
- CPU_PPC_602 = 0x00050000,
- CPU_PPC_603 = 0x00030000,
- CPU_PPC_603E = 0x00060000,
- CPU_PPC_603EV = 0x00070000,
- CPU_PPC_603R = 0x00071000,
- CPU_PPC_G2 = 0x80810000,
- CPU_PPC_G2LE = 0x80820000,
+ CPU_PPC_601 = 0x00010001,
+ CPU_PPC_602 = 0x00050100,
+ CPU_PPC_603 = 0x00030100,
+ CPU_PPC_603E = 0x00060101,
+ CPU_PPC_603P = 0x00070000,
+ CPU_PPC_603E7v = 0x00070100,
+ CPU_PPC_603E7v2 = 0x00070201,
+ CPU_PPC_603E7 = 0x00070200,
+ CPU_PPC_603R = 0x00071201,
+ CPU_PPC_G2 = 0x00810011,
+ CPU_PPC_G2H4 = 0x80811010,
+ CPU_PPC_G2gp = 0x80821010,
+ CPU_PPC_G2ls = 0x90810010,
+ CPU_PPC_G2LE = 0x80820010,
+ CPU_PPC_G2LEgp = 0x80822010,
+ CPU_PPC_G2LEls = 0xA0822010,
CPU_PPC_604 = 0x00040000,
- CPU_PPC_604E = 0x00090000,
- CPU_PPC_604R = 0x000a0000,
+ CPU_PPC_604E = 0x00090100, /* Also 2110 & 2120 */
+ CPU_PPC_604R = 0x000a0101,
/* PowerPC 74x/75x cores (aka G3) */
CPU_PPC_74x = 0x00080000,
- CPU_PPC_755 = 0x00083000,
+ CPU_PPC_740E = 0x00080100,
+ CPU_PPC_750E = 0x00080200,
+ CPU_PPC_755_10 = 0x00083100,
+ CPU_PPC_755_11 = 0x00083101,
+ CPU_PPC_755_20 = 0x00083200,
+ CPU_PPC_755D = 0x00083202,
+ CPU_PPC_755E = 0x00083203,
+#define CPU_PPC_755 CPU_PPC_755E
CPU_PPC_74xP = 0x10080000,
- CPU_PPC_750CXE22 = 0x00082202,
+ CPU_PPC_750CXE21 = 0x00082201,
+ CPU_PPC_750CXE22 = 0x00082212,
+ CPU_PPC_750CXE23 = 0x00082203,
CPU_PPC_750CXE24 = 0x00082214,
CPU_PPC_750CXE24b = 0x00083214,
CPU_PPC_750CXE31 = 0x00083211,
CPU_PPC_750CXE31b = 0x00083311,
#define CPU_PPC_750CXE CPU_PPC_750CXE31b
- CPU_PPC_750FX = 0x70000000,
- CPU_PPC_750GX = 0x70020000,
+ CPU_PPC_750CXR = 0x00083410,
+ CPU_PPC_750FX10 = 0x70000100,
+ CPU_PPC_750FX20 = 0x70000200,
+ CPU_PPC_750FX21 = 0x70000201,
+ CPU_PPC_750FX22 = 0x70000202,
+ CPU_PPC_750FX23 = 0x70000203,
+#define CPU_PPC_750FX CPU_PPC_750FX23
+ CPU_PPC_750FL = 0x700A0203,
+ CPU_PPC_750GX10 = 0x70020100,
+ CPU_PPC_750GX11 = 0x70020101,
+ CPU_PPC_750GX12 = 0x70020102,
+#define CPU_PPC_750GX CPU_PPC_750GX12
+ CPU_PPC_750GL = 0x70020102,
+ CPU_PPC_750L30 = 0x00088300,
+ CPU_PPC_750L32 = 0x00088302,
+ CPU_PPC_750CL = 0x00087200,
/* PowerPC 74xx cores (aka G4) */
- CPU_PPC_7400 = 0x000C0000,
- CPU_PPC_7410 = 0x800C0000,
- CPU_PPC_7441 = 0x80000200,
- CPU_PPC_7450 = 0x80000000,
+ CPU_PPC_7400 = 0x000C0100,
+ CPU_PPC_7410C = 0x800C1102,
+ CPU_PPC_7410D = 0x800C1103,
+ CPU_PPC_7410E = 0x800C1104,
+ CPU_PPC_7441 = 0x80000210,
+ CPU_PPC_7445 = 0x80010100,
+ CPU_PPC_7447 = 0x80020100,
+ CPU_PPC_7447A = 0x80030101,
+ CPU_PPC_7448 = 0x80040100,
+ CPU_PPC_7450 = 0x80000200,
+ CPU_PPC_7450b = 0x80000201,
CPU_PPC_7451 = 0x80000203,
- CPU_PPC_7455 = 0x80010000,
- CPU_PPC_7457 = 0x80020000,
+ CPU_PPC_7451G = 0x80000210,
+ CPU_PPC_7455 = 0x80010201,
+ CPU_PPC_7455F = 0x80010303,
+ CPU_PPC_7455G = 0x80010304,
+ CPU_PPC_7457 = 0x80020101,
+ CPU_PPC_7457C = 0x80020102,
CPU_PPC_7457A = 0x80030000,
/* 64 bits PowerPC */
CPU_PPC_620 = 0x00140000,
@@ -130,7 +253,21 @@
CPU_PPC_POWER5 = 0x003A0000,
CPU_PPC_POWER5P = 0x003B0000,
CPU_PPC_970 = 0x00390000,
- CPU_PPC_970FX = 0x003C0000,
+ CPU_PPC_970FX10 = 0x00391100,
+ CPU_PPC_970FX20 = 0x003C0200,
+ CPU_PPC_970FX21 = 0x003C0201,
+ CPU_PPC_970FX30 = 0x003C0300,
+ CPU_PPC_970FX31 = 0x003C0301,
+#define CPU_PPC_970FX CPU_PPC_970FX31
+ CPU_PPC_970MP10 = 0x00440100,
+ CPU_PPC_970MP11 = 0x00440101,
+#define CPU_PPC_970MP CPU_PPC_970MP11
+ CPU_PPC_CELL10 = 0x00700100,
+ CPU_PPC_CELL20 = 0x00700400,
+ CPU_PPC_CELL30 = 0x00700500,
+ CPU_PPC_CELL31 = 0x00700501,
+#define CPU_PPC_CELL32 CPU_PPC_CELL31
+#define CPU_PPC_CELL CPU_PPC_CELL32
CPU_PPC_RS64 = 0x00330000,
CPU_PPC_RS64II = 0x00340000,
CPU_PPC_RS64III = 0x00360000,
@@ -147,12 +284,28 @@
#endif
};
-/* System version register (used on MPC 8xx) */
+/* System version register (used on MPC 8xxx) */
enum {
PPC_SVR_8540 = 0x80300000,
- PPC_SVR_8541E = 0x807A0000,
- PPC_SVR_8555E = 0x80790000,
- PPC_SVR_8560 = 0x80700000,
+ PPC_SVR_8541E = 0x807A0010,
+ PPC_SVR_8543v10 = 0x80320010,
+ PPC_SVR_8543v11 = 0x80320011,
+ PPC_SVR_8543v20 = 0x80320020,
+ PPC_SVR_8543Ev10 = 0x803A0010,
+ PPC_SVR_8543Ev11 = 0x803A0011,
+ PPC_SVR_8543Ev20 = 0x803A0020,
+ PPC_SVR_8545 = 0x80310220,
+ PPC_SVR_8545E = 0x80390220,
+ PPC_SVR_8547E = 0x80390120,
+ PPC_SCR_8548v10 = 0x80310010,
+ PPC_SCR_8548v11 = 0x80310011,
+ PPC_SCR_8548v20 = 0x80310020,
+ PPC_SVR_8548Ev10 = 0x80390010,
+ PPC_SVR_8548Ev11 = 0x80390011,
+ PPC_SVR_8548Ev20 = 0x80390020,
+ PPC_SVR_8555E = 0x80790010,
+ PPC_SVR_8560v10 = 0x80700010,
+ PPC_SVR_8560v20 = 0x80700020,
};
/*****************************************************************************/
@@ -165,7 +318,7 @@
/* ld/st with reservation instructions */
/* cache control instructions */
/* spr/msr access instructions */
- PPC_INSNS_BASE = 0x00000001,
+ PPC_INSNS_BASE = 0x0000000000000001ULL,
#define PPC_INTEGER PPC_INSNS_BASE
#define PPC_FLOW PPC_INSNS_BASE
#define PPC_MEM PPC_INSNS_BASE
@@ -173,102 +326,133 @@
#define PPC_CACHE PPC_INSNS_BASE
#define PPC_MISC PPC_INSNS_BASE
/* floating point operations instructions */
- PPC_FLOAT = 0x00000002,
+ PPC_FLOAT = 0x0000000000000002ULL,
/* more floating point operations instructions */
- PPC_FLOAT_EXT = 0x00000004,
+ PPC_FLOAT_EXT = 0x0000000000000004ULL,
/* external control instructions */
- PPC_EXTERN = 0x00000008,
+ PPC_EXTERN = 0x0000000000000008ULL,
/* segment register access instructions */
- PPC_SEGMENT = 0x00000010,
+ PPC_SEGMENT = 0x0000000000000010ULL,
/* Optional cache control instructions */
- PPC_CACHE_OPT = 0x00000020,
+ PPC_CACHE_OPT = 0x0000000000000020ULL,
/* Optional floating point op instructions */
- PPC_FLOAT_OPT = 0x00000040,
+ PPC_FLOAT_OPT = 0x0000000000000040ULL,
/* Optional memory control instructions */
- PPC_MEM_TLBIA = 0x00000080,
- PPC_MEM_TLBIE = 0x00000100,
- PPC_MEM_TLBSYNC = 0x00000200,
+ PPC_MEM_TLBIA = 0x0000000000000080ULL,
+ PPC_MEM_TLBIE = 0x0000000000000100ULL,
+ PPC_MEM_TLBSYNC = 0x0000000000000200ULL,
/* eieio & sync */
- PPC_MEM_SYNC = 0x00000400,
+ PPC_MEM_SYNC = 0x0000000000000400ULL,
/* PowerPC 6xx TLB management instructions */
- PPC_6xx_TLB = 0x00000800,
+ PPC_6xx_TLB = 0x0000000000000800ULL,
/* Altivec support */
- PPC_ALTIVEC = 0x00001000,
+ PPC_ALTIVEC = 0x0000000000001000ULL,
/* Time base support */
- PPC_TB = 0x00002000,
+ PPC_TB = 0x0000000000002000ULL,
/* Embedded PowerPC dedicated instructions */
- PPC_4xx_COMMON = 0x00004000,
+ PPC_EMB_COMMON = 0x0000000000004000ULL,
/* PowerPC 40x exception model */
- PPC_40x_EXCP = 0x00008000,
+ PPC_40x_EXCP = 0x0000000000008000ULL,
/* PowerPC 40x specific instructions */
- PPC_40x_SPEC = 0x00010000,
+ PPC_40x_SPEC = 0x0000000000010000ULL,
/* PowerPC 405 Mac instructions */
- PPC_405_MAC = 0x00020000,
+ PPC_405_MAC = 0x0000000000020000ULL,
/* PowerPC 440 specific instructions */
- PPC_440_SPEC = 0x00040000,
+ PPC_440_SPEC = 0x0000000000040000ULL,
/* Specific extensions */
/* Power-to-PowerPC bridge (601) */
- PPC_POWER_BR = 0x00080000,
+ PPC_POWER_BR = 0x0000000000080000ULL,
/* PowerPC 602 specific */
- PPC_602_SPEC = 0x00100000,
+ PPC_602_SPEC = 0x0000000000100000ULL,
/* Deprecated instructions */
/* Original POWER instruction set */
- PPC_POWER = 0x00200000,
+ PPC_POWER = 0x0000000000200000ULL,
/* POWER2 instruction set extension */
- PPC_POWER2 = 0x00400000,
+ PPC_POWER2 = 0x0000000000400000ULL,
/* Power RTC support */
- PPC_POWER_RTC = 0x00800000,
+ PPC_POWER_RTC = 0x0000000000800000ULL,
/* 64 bits PowerPC instructions */
/* 64 bits PowerPC instruction set */
- PPC_64B = 0x01000000,
+ PPC_64B = 0x0000000001000000ULL,
/* 64 bits hypervisor extensions */
- PPC_64H = 0x02000000,
+ PPC_64H = 0x0000000002000000ULL,
/* 64 bits PowerPC "bridge" features */
- PPC_64_BRIDGE = 0x04000000,
+ PPC_64_BRIDGE = 0x0000000004000000ULL,
+ /* BookE (embedded) PowerPC specification */
+ PPC_BOOKE = 0x0000000008000000ULL,
+ /* eieio */
+ PPC_MEM_EIEIO = 0x0000000010000000ULL,
+ /* e500 vector instructions */
+ PPC_E500_VECTOR = 0x0000000020000000ULL,
+ /* PowerPC 4xx dedicated instructions */
+ PPC_4xx_COMMON = 0x0000000040000000ULL,
+ /* PowerPC 2.03 specification extensions */
+ PPC_203 = 0x0000000080000000ULL,
+ /* PowerPC 2.03 SPE extension */
+ PPC_SPE = 0x0000000100000000ULL,
+ /* PowerPC 2.03 SPE floating-point extension */
+ PPC_SPEFPU = 0x0000000200000000ULL,
+ /* SLB management */
+ PPC_SLBI = 0x0000000400000000ULL,
};
/* CPU run-time flags (MMU and exception model) */
enum {
/* MMU model */
-#define PPC_FLAGS_MMU_MASK (0x0000000F)
+ PPC_FLAGS_MMU_MASK = 0x000000FF,
/* Standard 32 bits PowerPC MMU */
- PPC_FLAGS_MMU_32B = 0x00000000,
+ PPC_FLAGS_MMU_32B = 0x00000000,
/* Standard 64 bits PowerPC MMU */
- PPC_FLAGS_MMU_64B = 0x00000001,
+ PPC_FLAGS_MMU_64B = 0x00000001,
/* PowerPC 601 MMU */
- PPC_FLAGS_MMU_601 = 0x00000002,
+ PPC_FLAGS_MMU_601 = 0x00000002,
/* PowerPC 6xx MMU with software TLB */
- PPC_FLAGS_MMU_SOFT_6xx = 0x00000003,
+ PPC_FLAGS_MMU_SOFT_6xx = 0x00000003,
/* PowerPC 4xx MMU with software TLB */
- PPC_FLAGS_MMU_SOFT_4xx = 0x00000004,
+ PPC_FLAGS_MMU_SOFT_4xx = 0x00000004,
/* PowerPC 403 MMU */
- PPC_FLAGS_MMU_403 = 0x00000005,
+ PPC_FLAGS_MMU_403 = 0x00000005,
+ /* BookE FSL MMU model */
+ PPC_FLAGS_MMU_BOOKE_FSL = 0x00000006,
+ /* BookE MMU model */
+ PPC_FLAGS_MMU_BOOKE = 0x00000007,
+ /* 64 bits "bridge" PowerPC MMU */
+ PPC_FLAGS_MMU_64BRIDGE = 0x00000008,
/* Exception model */
-#define PPC_FLAGS_EXCP_MASK (0x000000F0)
+ PPC_FLAGS_EXCP_MASK = 0x0000FF00,
/* Standard PowerPC exception model */
- PPC_FLAGS_EXCP_STD = 0x00000000,
+ PPC_FLAGS_EXCP_STD = 0x00000000,
/* PowerPC 40x exception model */
- PPC_FLAGS_EXCP_40x = 0x00000010,
+ PPC_FLAGS_EXCP_40x = 0x00000100,
/* PowerPC 601 exception model */
- PPC_FLAGS_EXCP_601 = 0x00000020,
+ PPC_FLAGS_EXCP_601 = 0x00000200,
/* PowerPC 602 exception model */
- PPC_FLAGS_EXCP_602 = 0x00000030,
+ PPC_FLAGS_EXCP_602 = 0x00000300,
/* PowerPC 603 exception model */
- PPC_FLAGS_EXCP_603 = 0x00000040,
+ PPC_FLAGS_EXCP_603 = 0x00000400,
/* PowerPC 604 exception model */
- PPC_FLAGS_EXCP_604 = 0x00000050,
+ PPC_FLAGS_EXCP_604 = 0x00000500,
/* PowerPC 7x0 exception model */
- PPC_FLAGS_EXCP_7x0 = 0x00000060,
+ PPC_FLAGS_EXCP_7x0 = 0x00000600,
/* PowerPC 7x5 exception model */
- PPC_FLAGS_EXCP_7x5 = 0x00000070,
+ PPC_FLAGS_EXCP_7x5 = 0x00000700,
/* PowerPC 74xx exception model */
- PPC_FLAGS_EXCP_74xx = 0x00000080,
+ PPC_FLAGS_EXCP_74xx = 0x00000800,
/* PowerPC 970 exception model */
- PPC_FLAGS_EXCP_970 = 0x00000090,
+ PPC_FLAGS_EXCP_970 = 0x00000900,
+ /* BookE exception model */
+ PPC_FLAGS_EXCP_BOOKE = 0x00000A00,
+ /* Input pins model */
+ PPC_FLAGS_INPUT_MASK = 0x000F0000,
+ PPC_FLAGS_INPUT_6xx = 0x00000000,
+ PPC_FLAGS_INPUT_BookE = 0x00010000,
+ PPC_FLAGS_INPUT_40x = 0x00020000,
+ PPC_FLAGS_INPUT_970 = 0x00030000,
};
#define PPC_MMU(env) (env->flags & PPC_FLAGS_MMU_MASK)
#define PPC_EXCP(env) (env->flags & PPC_FLAGS_EXCP_MASK)
+#define PPC_INPUT(env) (env->flags & PPC_FLAGS_INPUT_MASK)
/*****************************************************************************/
/* Supported instruction set definitions */
@@ -277,65 +461,92 @@
#define PPC_FLAGS_TODO (0x00000000)
/* PowerPC 40x instruction set */
-#define PPC_INSNS_4xx (PPC_INSNS_BASE | PPC_MEM_TLBSYNC | PPC_4xx_COMMON)
+#define PPC_INSNS_EMB (PPC_INSNS_BASE | PPC_MEM_TLBSYNC | PPC_EMB_COMMON)
/* PowerPC 401 */
#define PPC_INSNS_401 (PPC_INSNS_TODO)
#define PPC_FLAGS_401 (PPC_FLAGS_TODO)
/* PowerPC 403 */
-#define PPC_INSNS_403 (PPC_INSNS_4xx | PPC_MEM_SYNC | PPC_MEM_TLBIA | \
- PPC_40x_EXCP | PPC_40x_SPEC)
-#define PPC_FLAGS_403 (PPC_FLAGS_MMU_403 | PPC_FLAGS_EXCP_40x)
+#define PPC_INSNS_403 (PPC_INSNS_EMB | PPC_MEM_SYNC | PPC_MEM_EIEIO | \
+ PPC_MEM_TLBIA | PPC_4xx_COMMON | PPC_40x_EXCP | \
+ PPC_40x_SPEC)
+#define PPC_FLAGS_403 (PPC_FLAGS_MMU_403 | PPC_FLAGS_EXCP_40x | \
+ PPC_FLAGS_INPUT_40x)
/* PowerPC 405 */
-#define PPC_INSNS_405 (PPC_INSNS_4xx | PPC_MEM_SYNC | PPC_CACHE_OPT | \
- PPC_MEM_TLBIA | PPC_TB | PPC_40x_SPEC | PPC_40x_EXCP | \
+#define PPC_INSNS_405 (PPC_INSNS_EMB | PPC_MEM_SYNC | PPC_MEM_EIEIO | \
+ PPC_CACHE_OPT | PPC_MEM_TLBIA | PPC_TB | \
+ PPC_4xx_COMMON | PPC_40x_SPEC | PPC_40x_EXCP | \
PPC_405_MAC)
-#define PPC_FLAGS_405 (PPC_FLAGS_MMU_SOFT_4xx | PPC_FLAGS_EXCP_40x)
+#define PPC_FLAGS_405 (PPC_FLAGS_MMU_SOFT_4xx | PPC_FLAGS_EXCP_40x | \
+ PPC_FLAGS_INPUT_40x)
/* PowerPC 440 */
-#define PPC_INSNS_440 (PPC_INSNS_4xx | PPC_CACHE_OPT | PPC_405_MAC | \
- PPC_440_SPEC)
-#define PPC_FLAGS_440 (PPC_FLAGS_TODO)
+#define PPC_INSNS_440 (PPC_INSNS_EMB | PPC_CACHE_OPT | PPC_BOOKE | \
+ PPC_4xx_COMMON | PPC_405_MAC | PPC_440_SPEC)
+#define PPC_FLAGS_440 (PPC_FLAGS_MMU_BOOKE | PPC_FLAGS_EXCP_BOOKE | \
+ PPC_FLAGS_INPUT_BookE)
+/* Generic BookE PowerPC */
+#define PPC_INSNS_BOOKE (PPC_INSNS_EMB | PPC_BOOKE | PPC_MEM_EIEIO | \
+ PPC_FLOAT | PPC_FLOAT_OPT | PPC_CACHE_OPT)
+#define PPC_FLAGS_BOOKE (PPC_FLAGS_MMU_BOOKE | PPC_FLAGS_EXCP_BOOKE | \
+ PPC_FLAGS_INPUT_BookE)
+/* e500 core */
+#define PPC_INSNS_E500 (PPC_INSNS_EMB | PPC_BOOKE | PPC_MEM_EIEIO | \
+ PPC_CACHE_OPT | PPC_E500_VECTOR)
+#define PPC_FLAGS_E500 (PPC_FLAGS_MMU_SOFT_4xx | PPC_FLAGS_EXCP_40x | \
+ PPC_FLAGS_INPUT_BookE)
/* Non-embedded PowerPC */
#define PPC_INSNS_COMMON (PPC_INSNS_BASE | PPC_FLOAT | PPC_MEM_SYNC | \
- PPC_SEGMENT | PPC_MEM_TLBIE)
+ PPC_MEM_EIEIO | PPC_SEGMENT | PPC_MEM_TLBIE)
/* PowerPC 601 */
#define PPC_INSNS_601 (PPC_INSNS_COMMON | PPC_EXTERN | PPC_POWER_BR)
-#define PPC_FLAGS_601 (PPC_FLAGS_MMU_601 | PPC_FLAGS_EXCP_601)
+#define PPC_FLAGS_601 (PPC_FLAGS_MMU_601 | PPC_FLAGS_EXCP_601 | \
+ PPC_FLAGS_INPUT_6xx)
/* PowerPC 602 */
#define PPC_INSNS_602 (PPC_INSNS_COMMON | PPC_FLOAT_EXT | PPC_6xx_TLB | \
- PPC_MEM_TLBSYNC | PPC_TB)
-#define PPC_FLAGS_602 (PPC_FLAGS_MMU_SOFT_6xx | PPC_FLAGS_EXCP_602)
+ PPC_MEM_TLBSYNC | PPC_TB | PPC_602_SPEC)
+#define PPC_FLAGS_602 (PPC_FLAGS_MMU_SOFT_6xx | PPC_FLAGS_EXCP_602 | \
+ PPC_FLAGS_INPUT_6xx)
/* PowerPC 603 */
#define PPC_INSNS_603 (PPC_INSNS_COMMON | PPC_FLOAT_EXT | PPC_6xx_TLB | \
PPC_MEM_TLBSYNC | PPC_EXTERN | PPC_TB)
-#define PPC_FLAGS_603 (PPC_FLAGS_MMU_SOFT_6xx | PPC_FLAGS_EXCP_603)
+#define PPC_FLAGS_603 (PPC_FLAGS_MMU_SOFT_6xx | PPC_FLAGS_EXCP_603 | \
+ PPC_FLAGS_INPUT_6xx)
/* PowerPC G2 */
#define PPC_INSNS_G2 (PPC_INSNS_COMMON | PPC_FLOAT_EXT | PPC_6xx_TLB | \
PPC_MEM_TLBSYNC | PPC_EXTERN | PPC_TB)
-#define PPC_FLAGS_G2 (PPC_FLAGS_MMU_SOFT_6xx | PPC_FLAGS_EXCP_603)
+#define PPC_FLAGS_G2 (PPC_FLAGS_MMU_SOFT_6xx | PPC_FLAGS_EXCP_603 | \
+ PPC_FLAGS_INPUT_6xx)
/* PowerPC 604 */
#define PPC_INSNS_604 (PPC_INSNS_COMMON | PPC_FLOAT_EXT | PPC_EXTERN | \
PPC_MEM_TLBSYNC | PPC_TB)
-#define PPC_FLAGS_604 (PPC_FLAGS_MMU_32B | PPC_FLAGS_EXCP_604)
+#define PPC_FLAGS_604 (PPC_FLAGS_MMU_32B | PPC_FLAGS_EXCP_604 | \
+ PPC_FLAGS_INPUT_6xx)
/* PowerPC 740/750 (aka G3) */
#define PPC_INSNS_7x0 (PPC_INSNS_COMMON | PPC_FLOAT_EXT | PPC_EXTERN | \
PPC_MEM_TLBSYNC | PPC_TB)
-#define PPC_FLAGS_7x0 (PPC_FLAGS_MMU_32B | PPC_FLAGS_EXCP_7x0)
+#define PPC_FLAGS_7x0 (PPC_FLAGS_MMU_32B | PPC_FLAGS_EXCP_7x0 | \
+ PPC_FLAGS_INPUT_6xx)
/* PowerPC 745/755 */
#define PPC_INSNS_7x5 (PPC_INSNS_COMMON | PPC_FLOAT_EXT | PPC_EXTERN | \
PPC_MEM_TLBSYNC | PPC_TB | PPC_6xx_TLB)
-#define PPC_FLAGS_7x5 (PPC_FLAGS_MMU_SOFT_6xx | PPC_FLAGS_EXCP_7x5)
+#define PPC_FLAGS_7x5 (PPC_FLAGS_MMU_SOFT_6xx | PPC_FLAGS_EXCP_7x5 | \
+ PPC_FLAGS_INPUT_6xx)
/* PowerPC 74xx (aka G4) */
#define PPC_INSNS_74xx (PPC_INSNS_COMMON | PPC_FLOAT_EXT | PPC_ALTIVEC | \
PPC_MEM_TLBSYNC | PPC_TB)
-#define PPC_FLAGS_74xx (PPC_FLAGS_MMU_32B | PPC_FLAGS_EXCP_74xx)
+#define PPC_FLAGS_74xx (PPC_FLAGS_MMU_32B | PPC_FLAGS_EXCP_74xx | \
+ PPC_FLAGS_INPUT_6xx)
+/* PowerPC 970 (aka G5) */
+#define PPC_INSNS_970 (PPC_INSNS_COMMON | PPC_FLOAT_EXT | PPC_FLOAT_OPT | \
+ PPC_ALTIVEC | PPC_MEM_TLBSYNC | PPC_TB | \
+ PPC_64B | PPC_64_BRIDGE | PPC_SLBI)
+#define PPC_FLAGS_970 (PPC_FLAGS_MMU_64BRIDGE | PPC_FLAGS_EXCP_970 | \
+ PPC_FLAGS_INPUT_970)
/* Default PowerPC will be 604/970 */
#define PPC_INSNS_PPC32 PPC_INSNS_604
#define PPC_FLAGS_PPC32 PPC_FLAGS_604
-#if 0
#define PPC_INSNS_PPC64 PPC_INSNS_970
#define PPC_FLAGS_PPC64 PPC_FLAGS_970
-#endif
#define PPC_INSNS_DEFAULT PPC_INSNS_604
#define PPC_FLAGS_DEFAULT PPC_FLAGS_604
typedef struct ppc_def_t ppc_def_t;
@@ -348,13 +559,16 @@
typedef struct ppc_spr_t ppc_spr_t;
typedef struct ppc_dcr_t ppc_dcr_t;
typedef struct ppc_avr_t ppc_avr_t;
+typedef union ppc_tlb_t ppc_tlb_t;
/* SPR access micro-ops generations callbacks */
struct ppc_spr_t {
void (*uea_read)(void *opaque, int spr_num);
void (*uea_write)(void *opaque, int spr_num);
+#if !defined(CONFIG_USER_ONLY)
void (*oea_read)(void *opaque, int spr_num);
void (*oea_write)(void *opaque, int spr_num);
+#endif
const unsigned char *name;
};
@@ -364,46 +578,58 @@
};
/* Software TLB cache */
-typedef struct ppc_tlb_t ppc_tlb_t;
-struct ppc_tlb_t {
- /* Physical page number */
+typedef struct ppc6xx_tlb_t ppc6xx_tlb_t;
+struct ppc6xx_tlb_t {
+ target_ulong pte0;
+ target_ulong pte1;
+ target_ulong EPN;
+};
+
+typedef struct ppcemb_tlb_t ppcemb_tlb_t;
+struct ppcemb_tlb_t {
target_phys_addr_t RPN;
- /* Virtual page number */
- target_ulong VPN;
- /* Page size */
+ target_ulong EPN;
+ target_ulong PID;
target_ulong size;
- /* Protection bits */
- int prot;
- int is_user;
- uint32_t private;
- uint32_t flags;
+ uint32_t prot;
+ uint32_t attr; /* Storage attributes */
};
+union ppc_tlb_t {
+ ppc6xx_tlb_t tlb6;
+ ppcemb_tlb_t tlbe;
+};
+
/*****************************************************************************/
/* Machine state register bits definition */
-#define MSR_SF 63 /* Sixty-four-bit mode */
+#define MSR_SF 63 /* Sixty-four-bit mode hflags */
#define MSR_ISF 61 /* Sixty-four-bit interrupt mode on 630 */
-#define MSR_HV 60 /* hypervisor state */
-#define MSR_VR 25 /* altivec available */
-#define MSR_AP 23 /* Access privilege state on 602 */
-#define MSR_SA 22 /* Supervisor access mode on 602 */
+#define MSR_HV 60 /* hypervisor state hflags */
+#define MSR_CM 31 /* Computation mode for BookE hflags */
+#define MSR_ICM 30 /* Interrupt computation mode for BookE */
+#define MSR_UCLE 26 /* User-mode cache lock enable for BookE */
+#define MSR_VR 25 /* altivec available hflags */
+#define MSR_SPE 25 /* SPE enable for BookE hflags */
+#define MSR_AP 23 /* Access privilege state on 602 hflags */
+#define MSR_SA 22 /* Supervisor access mode on 602 hflags */
#define MSR_KEY 19 /* key bit on 603e */
#define MSR_POW 18 /* Power management */
#define MSR_WE 18 /* Wait state enable on embedded PowerPC */
#define MSR_TGPR 17 /* TGPR usage on 602/603 */
-#define MSR_TLB 17 /* TLB on ? */
+#define MSR_TLB 17 /* TLB update on ? */
#define MSR_CE 17 /* Critical interrupt enable on embedded PowerPC */
#define MSR_ILE 16 /* Interrupt little-endian mode */
#define MSR_EE 15 /* External interrupt enable */
-#define MSR_PR 14 /* Problem state */
-#define MSR_FP 13 /* Floating point available */
+#define MSR_PR 14 /* Problem state hflags */
+#define MSR_FP 13 /* Floating point available hflags */
#define MSR_ME 12 /* Machine check interrupt enable */
-#define MSR_FE0 11 /* Floating point exception mode 0 */
-#define MSR_SE 10 /* Single-step trace enable */
+#define MSR_FE0 11 /* Floating point exception mode 0 hflags */
+#define MSR_SE 10 /* Single-step trace enable hflags */
#define MSR_DWE 10 /* Debug wait enable on 405 */
-#define MSR_BE 9 /* Branch trace enable */
+#define MSR_UBLE 10 /* User BTB lock enable on e500 */
+#define MSR_BE 9 /* Branch trace enable hflags */
#define MSR_DE 9 /* Debug interrupts enable on embedded PowerPC */
-#define MSR_FE1 8 /* Floating point exception mode 1 */
+#define MSR_FE1 8 /* Floating point exception mode 1 hflags */
#define MSR_AL 7 /* AL bit on POWER */
#define MSR_IP 6 /* Interrupt prefix */
#define MSR_IR 5 /* Instruction relocate */
@@ -415,42 +641,47 @@
#define MSR_PX 2 /* Protection exclusive on 403 */
#define MSR_PMM 2 /* Performance monitor mark on POWER */
#define MSR_RI 1 /* Recoverable interrupt */
-#define MSR_LE 0 /* Little-endian mode */
+#define MSR_LE 0 /* Little-endian mode hflags */
#define msr_sf env->msr[MSR_SF]
#define msr_isf env->msr[MSR_ISF]
#define msr_hv env->msr[MSR_HV]
+#define msr_cm env->msr[MSR_CM]
+#define msr_icm env->msr[MSR_ICM]
+#define msr_ucle env->msr[MSR_UCLE]
#define msr_vr env->msr[MSR_VR]
+#define msr_spe env->msr[MSR_SPE]
#define msr_ap env->msr[MSR_AP]
#define msr_sa env->msr[MSR_SA]
#define msr_key env->msr[MSR_KEY]
-#define msr_pow env->msr[MSR_POW]
+#define msr_pow env->msr[MSR_POW]
#define msr_we env->msr[MSR_WE]
#define msr_tgpr env->msr[MSR_TGPR]
#define msr_tlb env->msr[MSR_TLB]
#define msr_ce env->msr[MSR_CE]
-#define msr_ile env->msr[MSR_ILE]
-#define msr_ee env->msr[MSR_EE]
-#define msr_pr env->msr[MSR_PR]
-#define msr_fp env->msr[MSR_FP]
-#define msr_me env->msr[MSR_ME]
-#define msr_fe0 env->msr[MSR_FE0]
-#define msr_se env->msr[MSR_SE]
+#define msr_ile env->msr[MSR_ILE]
+#define msr_ee env->msr[MSR_EE]
+#define msr_pr env->msr[MSR_PR]
+#define msr_fp env->msr[MSR_FP]
+#define msr_me env->msr[MSR_ME]
+#define msr_fe0 env->msr[MSR_FE0]
+#define msr_se env->msr[MSR_SE]
#define msr_dwe env->msr[MSR_DWE]
-#define msr_be env->msr[MSR_BE]
+#define msr_uble env->msr[MSR_UBLE]
+#define msr_be env->msr[MSR_BE]
#define msr_de env->msr[MSR_DE]
-#define msr_fe1 env->msr[MSR_FE1]
+#define msr_fe1 env->msr[MSR_FE1]
#define msr_al env->msr[MSR_AL]
-#define msr_ip env->msr[MSR_IP]
-#define msr_ir env->msr[MSR_IR]
+#define msr_ip env->msr[MSR_IP]
+#define msr_ir env->msr[MSR_IR]
#define msr_is env->msr[MSR_IS]
-#define msr_dr env->msr[MSR_DR]
+#define msr_dr env->msr[MSR_DR]
#define msr_ds env->msr[MSR_DS]
#define msr_pe env->msr[MSR_PE]
#define msr_ep env->msr[MSR_EP]
#define msr_px env->msr[MSR_PX]
#define msr_pmm env->msr[MSR_PMM]
-#define msr_ri env->msr[MSR_RI]
-#define msr_le env->msr[MSR_LE]
+#define msr_ri env->msr[MSR_RI]
+#define msr_le env->msr[MSR_LE]
/*****************************************************************************/
/* The whole PowerPC CPU context */
@@ -458,14 +689,16 @@
/* First are the most commonly used resources
* during translated code execution
*/
-#if TARGET_LONG_BITS > HOST_LONG_BITS
+#if TARGET_GPR_BITS > HOST_LONG_BITS
/* temporary fixed-point registers
* used to emulate 64 bits target on 32 bits hosts
- */
+ */
target_ulong t0, t1, t2;
#endif
+ ppc_avr_t t0_avr, t1_avr, t2_avr;
+
/* general purpose registers */
- target_ulong gpr[32];
+ ppc_gpr_t gpr[32];
/* LR */
target_ulong lr;
/* CTR */
@@ -482,10 +715,10 @@
/* machine state register */
uint8_t msr[64];
/* temporary general purpose registers */
- target_ulong tgpr[4]; /* Used to speed-up TLB assist handlers */
+ ppc_gpr_t tgpr[4]; /* Used to speed-up TLB assist handlers */
/* Floating point execution context */
- /* temporary float registers */
+ /* temporary float registers */
float64 ft0;
float64 ft1;
float64 ft2;
@@ -519,23 +752,25 @@
/* Altivec registers */
ppc_avr_t avr[32];
uint32_t vscr;
+ /* SPE registers */
+ ppc_gpr_t spe_acc;
+ float_status spe_status;
+ uint32_t spe_fscr;
/* Internal devices resources */
/* Time base and decrementer */
ppc_tb_t *tb_env;
/* Device control registers */
- int (*dcr_read)(ppc_dcr_t *dcr_env, int dcr_num, target_ulong *val);
- int (*dcr_write)(ppc_dcr_t *dcr_env, int dcr_num, target_ulong val);
ppc_dcr_t *dcr_env;
/* PowerPC TLB registers (for 4xx and 60x software driven TLBs) */
- int nb_tlb;
- int nb_ways, last_way;
- ppc_tlb_t tlb[128];
- /* Callbacks for specific checks on some implementations */
- int (*tlb_check_more)(CPUPPCState *env, struct ppc_tlb_t *tlb, int *prot,
- target_ulong vaddr, int rw, int acc_type,
- int is_user);
+ int nb_tlb; /* Total number of TLB */
+ int tlb_per_way; /* Speed-up helper: used to avoid divisions at run time */
+ int nb_ways; /* Number of ways in the TLB set */
+ int last_way; /* Last used way used to allocate TLB in a LRU way */
+ int id_tlbs; /* If 1, MMU has separated TLBs for instructions & data */
+ int nb_pids; /* Number of available PID registers */
+ ppc_tlb_t *tlb; /* TLB is optional. Allocate them only if needed */
/* 403 dedicated access protection registers */
target_ulong pb[4];
@@ -547,6 +782,14 @@
int exception_index;
int error_code;
int interrupt_request;
+ uint32_t pending_interrupts;
+#if !defined(CONFIG_USER_ONLY)
+ /* This is the IRQ controller, which is implementation dependant
+ * and only relevant when emulating a complete machine.
+ */
+ uint32_t irq_input_state;
+ void **irq_inputs;
+#endif
/* Those resources are used only during code translation */
/* Next instruction pointer */
@@ -568,6 +811,16 @@
int (*osi_call)(struct CPUPPCState *env);
};
+/* Context used internally during MMU translations */
+typedef struct mmu_ctx_t mmu_ctx_t;
+struct mmu_ctx_t {
+ target_phys_addr_t raddr; /* Real address */
+ int prot; /* Protection bits */
+ target_phys_addr_t pg_addr[2]; /* PTE tables base addresses */
+ target_ulong ptem; /* Virtual segment ID | API */
+ int key; /* Access key */
+};
+
/*****************************************************************************/
CPUPPCState *cpu_ppc_init(void);
int cpu_ppc_exec(CPUPPCState *s);
@@ -575,15 +828,16 @@
/* you can call this signal handler from your SIGBUS and SIGSEGV
signal handlers to inform the virtual CPU of exceptions. non zero
is returned if the signal was handled by the virtual CPU. */
-struct siginfo;
-int cpu_ppc_signal_handler(int host_signum, struct siginfo *info,
+int cpu_ppc_signal_handler(int host_signum, void *pinfo,
void *puc);
void do_interrupt (CPUPPCState *env);
+void ppc_hw_interrupt (CPUPPCState *env);
void cpu_loop_exit(void);
void dump_stack (CPUPPCState *env);
+#if !defined(CONFIG_USER_ONLY)
target_ulong do_load_ibatu (CPUPPCState *env, int nr);
target_ulong do_load_ibatl (CPUPPCState *env, int nr);
void do_store_ibatu (CPUPPCState *env, int nr, target_ulong value);
@@ -592,25 +846,25 @@
target_ulong do_load_dbatl (CPUPPCState *env, int nr);
void do_store_dbatu (CPUPPCState *env, int nr, target_ulong value);
void do_store_dbatl (CPUPPCState *env, int nr, target_ulong value);
-
-target_ulong do_load_nip (CPUPPCState *env);
-void do_store_nip (CPUPPCState *env, target_ulong value);
target_ulong do_load_sdr1 (CPUPPCState *env);
void do_store_sdr1 (CPUPPCState *env, target_ulong value);
-target_ulong do_load_asr (CPUPPCState *env);
-void do_store_asr (CPUPPCState *env, target_ulong value);
+#if defined(TARGET_PPC64)
+target_ulong ppc_load_asr (CPUPPCState *env);
+void ppc_store_asr (CPUPPCState *env, target_ulong value);
+#endif
target_ulong do_load_sr (CPUPPCState *env, int srnum);
void do_store_sr (CPUPPCState *env, int srnum, target_ulong value);
-uint32_t do_load_cr (CPUPPCState *env);
-void do_store_cr (CPUPPCState *env, uint32_t value, uint32_t mask);
-uint32_t do_load_xer (CPUPPCState *env);
-void do_store_xer (CPUPPCState *env, uint32_t value);
+#endif
+uint32_t ppc_load_xer (CPUPPCState *env);
+void ppc_store_xer (CPUPPCState *env, uint32_t value);
target_ulong do_load_msr (CPUPPCState *env);
void do_store_msr (CPUPPCState *env, target_ulong value);
-float64 do_load_fpscr (CPUPPCState *env);
-void do_store_fpscr (CPUPPCState *env, float64 f, uint32_t mask);
+void ppc_store_msr_32 (CPUPPCState *env, uint32_t value);
void do_compute_hflags (CPUPPCState *env);
+void cpu_ppc_reset (void *opaque);
+CPUPPCState *cpu_ppc_init (void);
+void cpu_ppc_close(CPUPPCState *env);
int ppc_find_by_name (const unsigned char *name, ppc_def_t **def);
int ppc_find_by_pvr (uint32_t apvr, ppc_def_t **def);
@@ -625,9 +879,26 @@
void cpu_ppc_store_tbl (CPUPPCState *env, uint32_t value);
uint32_t cpu_ppc_load_decr (CPUPPCState *env);
void cpu_ppc_store_decr (CPUPPCState *env, uint32_t value);
+uint32_t cpu_ppc601_load_rtcl (CPUPPCState *env);
+uint32_t cpu_ppc601_load_rtcu (CPUPPCState *env);
+#if !defined(CONFIG_USER_ONLY)
+void cpu_ppc601_store_rtcl (CPUPPCState *env, uint32_t value);
+void cpu_ppc601_store_rtcu (CPUPPCState *env, uint32_t value);
+target_ulong load_40x_pit (CPUPPCState *env);
+void store_40x_pit (CPUPPCState *env, target_ulong val);
+void store_40x_dbcr0 (CPUPPCState *env, uint32_t val);
+void store_40x_sler (CPUPPCState *env, uint32_t val);
+void store_booke_tcr (CPUPPCState *env, target_ulong val);
+void store_booke_tsr (CPUPPCState *env, target_ulong val);
+void ppc_tlb_invalidate_all (CPUPPCState *env);
+int ppcemb_tlb_search (CPUPPCState *env, target_ulong address);
#endif
+#endif
-#define TARGET_PAGE_BITS 12
+/* Device control registers */
+int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, target_ulong *valp);
+int ppc_dcr_write (ppc_dcr_t *dcr_env, int dcrn, target_ulong val);
+
#include "cpu-all.h"
/*****************************************************************************/
@@ -646,261 +917,308 @@
#define xer_bc env->xer[0]
/* SPR definitions */
-#define SPR_MQ (0x000)
-#define SPR_XER (0x001)
-#define SPR_601_VRTCU (0x004)
-#define SPR_601_VRTCL (0x005)
-#define SPR_601_UDECR (0x006)
-#define SPR_LR (0x008)
-#define SPR_CTR (0x009)
-#define SPR_DSISR (0x012)
-#define SPR_DAR (0x013)
-#define SPR_601_RTCU (0x014)
-#define SPR_601_RTCL (0x015)
-#define SPR_DECR (0x016)
-#define SPR_SDR1 (0x019)
-#define SPR_SRR0 (0x01A)
-#define SPR_SRR1 (0x01B)
-#define SPR_440_PID (0x030)
-#define SPR_440_DECAR (0x036)
-#define SPR_CSRR0 (0x03A)
-#define SPR_CSRR1 (0x03B)
-#define SPR_440_DEAR (0x03D)
-#define SPR_440_ESR (0x03E)
-#define SPR_440_IVPR (0x03F)
-#define SPR_8xx_EIE (0x050)
-#define SPR_8xx_EID (0x051)
-#define SPR_8xx_NRE (0x052)
-#define SPR_58x_CMPA (0x090)
-#define SPR_58x_CMPB (0x091)
-#define SPR_58x_CMPC (0x092)
-#define SPR_58x_CMPD (0x093)
-#define SPR_58x_ICR (0x094)
-#define SPR_58x_DER (0x094)
-#define SPR_58x_COUNTA (0x096)
-#define SPR_58x_COUNTB (0x097)
-#define SPR_58x_CMPE (0x098)
-#define SPR_58x_CMPF (0x099)
-#define SPR_58x_CMPG (0x09A)
-#define SPR_58x_CMPH (0x09B)
-#define SPR_58x_LCTRL1 (0x09C)
-#define SPR_58x_LCTRL2 (0x09D)
-#define SPR_58x_ICTRL (0x09E)
-#define SPR_58x_BAR (0x09F)
-#define SPR_VRSAVE (0x100)
-#define SPR_USPRG0 (0x100)
-#define SPR_USPRG4 (0x104)
-#define SPR_USPRG5 (0x105)
-#define SPR_USPRG6 (0x106)
-#define SPR_USPRG7 (0x107)
-#define SPR_VTBL (0x10C)
-#define SPR_VTBU (0x10D)
-#define SPR_SPRG0 (0x110)
-#define SPR_SPRG1 (0x111)
-#define SPR_SPRG2 (0x112)
-#define SPR_SPRG3 (0x113)
-#define SPR_SPRG4 (0x114)
-#define SPR_SCOMC (0x114)
-#define SPR_SPRG5 (0x115)
-#define SPR_SCOMD (0x115)
-#define SPR_SPRG6 (0x116)
-#define SPR_SPRG7 (0x117)
-#define SPR_ASR (0x118)
-#define SPR_EAR (0x11A)
-#define SPR_TBL (0x11C)
-#define SPR_TBU (0x11D)
-#define SPR_SVR (0x11E)
-#define SPR_440_PIR (0x11E)
-#define SPR_PVR (0x11F)
-#define SPR_HSPRG0 (0x130)
-#define SPR_440_DBSR (0x130)
-#define SPR_HSPRG1 (0x131)
-#define SPR_440_DBCR0 (0x134)
-#define SPR_IBCR (0x135)
-#define SPR_440_DBCR1 (0x135)
-#define SPR_DBCR (0x136)
-#define SPR_HDEC (0x136)
-#define SPR_440_DBCR2 (0x136)
-#define SPR_HIOR (0x137)
-#define SPR_MBAR (0x137)
-#define SPR_RMOR (0x138)
-#define SPR_440_IAC1 (0x138)
-#define SPR_HRMOR (0x139)
-#define SPR_440_IAC2 (0x139)
-#define SPR_HSSR0 (0x13A)
-#define SPR_440_IAC3 (0x13A)
-#define SPR_HSSR1 (0x13B)
-#define SPR_440_IAC4 (0x13B)
-#define SPR_LPCR (0x13C)
-#define SPR_440_DAC1 (0x13C)
-#define SPR_LPIDR (0x13D)
-#define SPR_DABR2 (0x13D)
-#define SPR_440_DAC2 (0x13D)
-#define SPR_440_DVC1 (0x13E)
-#define SPR_440_DVC2 (0x13F)
-#define SPR_440_TSR (0x150)
-#define SPR_440_TCR (0x154)
-#define SPR_440_IVOR0 (0x190)
-#define SPR_440_IVOR1 (0x191)
-#define SPR_440_IVOR2 (0x192)
-#define SPR_440_IVOR3 (0x193)
-#define SPR_440_IVOR4 (0x194)
-#define SPR_440_IVOR5 (0x195)
-#define SPR_440_IVOR6 (0x196)
-#define SPR_440_IVOR7 (0x197)
-#define SPR_440_IVOR8 (0x198)
-#define SPR_440_IVOR9 (0x199)
-#define SPR_440_IVOR10 (0x19A)
-#define SPR_440_IVOR11 (0x19B)
-#define SPR_440_IVOR12 (0x19C)
-#define SPR_440_IVOR13 (0x19D)
-#define SPR_440_IVOR14 (0x19E)
-#define SPR_440_IVOR15 (0x19F)
-#define SPR_IBAT0U (0x210)
-#define SPR_IBAT0L (0x211)
-#define SPR_IBAT1U (0x212)
-#define SPR_IBAT1L (0x213)
-#define SPR_IBAT2U (0x214)
-#define SPR_IBAT2L (0x215)
-#define SPR_IBAT3U (0x216)
-#define SPR_IBAT3L (0x217)
-#define SPR_DBAT0U (0x218)
-#define SPR_DBAT0L (0x219)
-#define SPR_DBAT1U (0x21A)
-#define SPR_DBAT1L (0x21B)
-#define SPR_DBAT2U (0x21C)
-#define SPR_DBAT2L (0x21D)
-#define SPR_DBAT3U (0x21E)
-#define SPR_DBAT3L (0x21F)
-#define SPR_IBAT4U (0x230)
-#define SPR_IBAT4L (0x231)
-#define SPR_IBAT5U (0x232)
-#define SPR_IBAT5L (0x233)
-#define SPR_IBAT6U (0x234)
-#define SPR_IBAT6L (0x235)
-#define SPR_IBAT7U (0x236)
-#define SPR_IBAT7L (0x237)
-#define SPR_DBAT4U (0x238)
-#define SPR_DBAT4L (0x239)
-#define SPR_DBAT5U (0x23A)
-#define SPR_DBAT5L (0x23B)
-#define SPR_DBAT6U (0x23C)
-#define SPR_DBAT6L (0x23D)
-#define SPR_DBAT7U (0x23E)
-#define SPR_DBAT7L (0x23F)
-#define SPR_440_INV0 (0x370)
-#define SPR_440_INV1 (0x371)
-#define SPR_440_INV2 (0x372)
-#define SPR_440_INV3 (0x373)
-#define SPR_440_IVT0 (0x374)
-#define SPR_440_IVT1 (0x375)
-#define SPR_440_IVT2 (0x376)
-#define SPR_440_IVT3 (0x377)
-#define SPR_440_DNV0 (0x390)
-#define SPR_440_DNV1 (0x391)
-#define SPR_440_DNV2 (0x392)
-#define SPR_440_DNV3 (0x393)
-#define SPR_440_DVT0 (0x394)
-#define SPR_440_DVT1 (0x395)
-#define SPR_440_DVT2 (0x396)
-#define SPR_440_DVT3 (0x397)
-#define SPR_440_DVLIM (0x398)
-#define SPR_440_IVLIM (0x399)
-#define SPR_440_RSTCFG (0x39B)
-#define SPR_440_DCBTRL (0x39C)
-#define SPR_440_DCBTRH (0x39D)
-#define SPR_440_ICBTRL (0x39E)
-#define SPR_440_ICBTRH (0x39F)
-#define SPR_UMMCR0 (0x3A8)
-#define SPR_UPMC1 (0x3A9)
-#define SPR_UPMC2 (0x3AA)
-#define SPR_USIA (0x3AB)
-#define SPR_UMMCR1 (0x3AC)
-#define SPR_UPMC3 (0x3AD)
-#define SPR_UPMC4 (0x3AE)
-#define SPR_USDA (0x3AF)
-#define SPR_40x_ZPR (0x3B0)
-#define SPR_40x_PID (0x3B1)
-#define SPR_440_MMUCR (0x3B2)
-#define SPR_4xx_CCR0 (0x3B3)
-#define SPR_405_IAC3 (0x3B4)
-#define SPR_405_IAC4 (0x3B5)
-#define SPR_405_DVC1 (0x3B6)
-#define SPR_405_DVC2 (0x3B7)
-#define SPR_MMCR0 (0x3B8)
-#define SPR_PMC1 (0x3B9)
-#define SPR_40x_SGR (0x3B9)
-#define SPR_PMC2 (0x3BA)
-#define SPR_40x_DCWR (0x3BA)
-#define SPR_SIA (0x3BB)
-#define SPR_405_SLER (0x3BB)
-#define SPR_MMCR1 (0x3BC)
-#define SPR_405_SU0R (0x3BC)
-#define SPR_PMC3 (0x3BD)
-#define SPR_405_DBCR1 (0x3BD)
-#define SPR_PMC4 (0x3BE)
-#define SPR_SDA (0x3BF)
-#define SPR_403_VTBL (0x3CC)
-#define SPR_403_VTBU (0x3CD)
-#define SPR_DMISS (0x3D0)
-#define SPR_DCMP (0x3D1)
-#define SPR_DHASH1 (0x3D2)
-#define SPR_DHASH2 (0x3D3)
-#define SPR_4xx_ICDBDR (0x3D3)
-#define SPR_IMISS (0x3D4)
-#define SPR_40x_ESR (0x3D4)
-#define SPR_ICMP (0x3D5)
-#define SPR_40x_DEAR (0x3D5)
-#define SPR_RPA (0x3D6)
-#define SPR_40x_EVPR (0x3D6)
-#define SPR_403_CDBCR (0x3D7)
-#define SPR_TCR (0x3D8)
-#define SPR_40x_TSR (0x3D8)
-#define SPR_IBR (0x3DA)
-#define SPR_40x_TCR (0x3DA)
-#define SPR_ESASR (0x3DB)
-#define SPR_40x_PIT (0x3DB)
-#define SPR_403_TBL (0x3DC)
-#define SPR_403_TBU (0x3DD)
-#define SPR_SEBR (0x3DE)
-#define SPR_40x_SRR2 (0x3DE)
-#define SPR_SER (0x3DF)
-#define SPR_40x_SRR3 (0x3DF)
-#define SPR_HID0 (0x3F0)
-#define SPR_40x_DBSR (0x3F0)
-#define SPR_HID1 (0x3F1)
-#define SPR_IABR (0x3F2)
-#define SPR_40x_DBCR0 (0x3F2)
-#define SPR_601_HID2 (0x3F2)
-#define SPR_HID2 (0x3F3)
-#define SPR_440_DBDR (0x3F3)
-#define SPR_40x_IAC1 (0x3F4)
-#define SPR_DABR (0x3F5)
+#define SPR_MQ (0x000)
+#define SPR_XER (0x001)
+#define SPR_601_VRTCU (0x004)
+#define SPR_601_VRTCL (0x005)
+#define SPR_601_UDECR (0x006)
+#define SPR_LR (0x008)
+#define SPR_CTR (0x009)
+#define SPR_DSISR (0x012)
+#define SPR_DAR (0x013)
+#define SPR_601_RTCU (0x014)
+#define SPR_601_RTCL (0x015)
+#define SPR_DECR (0x016)
+#define SPR_SDR1 (0x019)
+#define SPR_SRR0 (0x01A)
+#define SPR_SRR1 (0x01B)
+#define SPR_BOOKE_PID (0x030)
+#define SPR_BOOKE_DECAR (0x036)
+#define SPR_BOOKE_CSRR0 (0x03A)
+#define SPR_BOOKE_CSRR1 (0x03B)
+#define SPR_BOOKE_DEAR (0x03D)
+#define SPR_BOOKE_ESR (0x03E)
+#define SPR_BOOKE_IVPR (0x03F)
+#define SPR_8xx_EIE (0x050)
+#define SPR_8xx_EID (0x051)
+#define SPR_8xx_NRE (0x052)
+#define SPR_58x_CMPA (0x090)
+#define SPR_58x_CMPB (0x091)
+#define SPR_58x_CMPC (0x092)
+#define SPR_58x_CMPD (0x093)
+#define SPR_58x_ICR (0x094)
+#define SPR_58x_DER (0x094)
+#define SPR_58x_COUNTA (0x096)
+#define SPR_58x_COUNTB (0x097)
+#define SPR_58x_CMPE (0x098)
+#define SPR_58x_CMPF (0x099)
+#define SPR_58x_CMPG (0x09A)
+#define SPR_58x_CMPH (0x09B)
+#define SPR_58x_LCTRL1 (0x09C)
+#define SPR_58x_LCTRL2 (0x09D)
+#define SPR_58x_ICTRL (0x09E)
+#define SPR_58x_BAR (0x09F)
+#define SPR_VRSAVE (0x100)
+#define SPR_USPRG0 (0x100)
+#define SPR_USPRG1 (0x101)
+#define SPR_USPRG2 (0x102)
+#define SPR_USPRG3 (0x103)
+#define SPR_USPRG4 (0x104)
+#define SPR_USPRG5 (0x105)
+#define SPR_USPRG6 (0x106)
+#define SPR_USPRG7 (0x107)
+#define SPR_VTBL (0x10C)
+#define SPR_VTBU (0x10D)
+#define SPR_SPRG0 (0x110)
+#define SPR_SPRG1 (0x111)
+#define SPR_SPRG2 (0x112)
+#define SPR_SPRG3 (0x113)
+#define SPR_SPRG4 (0x114)
+#define SPR_SCOMC (0x114)
+#define SPR_SPRG5 (0x115)
+#define SPR_SCOMD (0x115)
+#define SPR_SPRG6 (0x116)
+#define SPR_SPRG7 (0x117)
+#define SPR_ASR (0x118)
+#define SPR_EAR (0x11A)
+#define SPR_TBL (0x11C)
+#define SPR_TBU (0x11D)
+#define SPR_SVR (0x11E)
+#define SPR_BOOKE_PIR (0x11E)
+#define SPR_PVR (0x11F)
+#define SPR_HSPRG0 (0x130)
+#define SPR_BOOKE_DBSR (0x130)
+#define SPR_HSPRG1 (0x131)
+#define SPR_BOOKE_DBCR0 (0x134)
+#define SPR_IBCR (0x135)
+#define SPR_BOOKE_DBCR1 (0x135)
+#define SPR_DBCR (0x136)
+#define SPR_HDEC (0x136)
+#define SPR_BOOKE_DBCR2 (0x136)
+#define SPR_HIOR (0x137)
+#define SPR_MBAR (0x137)
+#define SPR_RMOR (0x138)
+#define SPR_BOOKE_IAC1 (0x138)
+#define SPR_HRMOR (0x139)
+#define SPR_BOOKE_IAC2 (0x139)
+#define SPR_HSSR0 (0x13A)
+#define SPR_BOOKE_IAC3 (0x13A)
+#define SPR_HSSR1 (0x13B)
+#define SPR_BOOKE_IAC4 (0x13B)
+#define SPR_LPCR (0x13C)
+#define SPR_BOOKE_DAC1 (0x13C)
+#define SPR_LPIDR (0x13D)
+#define SPR_DABR2 (0x13D)
+#define SPR_BOOKE_DAC2 (0x13D)
+#define SPR_BOOKE_DVC1 (0x13E)
+#define SPR_BOOKE_DVC2 (0x13F)
+#define SPR_BOOKE_TSR (0x150)
+#define SPR_BOOKE_TCR (0x154)
+#define SPR_BOOKE_IVOR0 (0x190)
+#define SPR_BOOKE_IVOR1 (0x191)
+#define SPR_BOOKE_IVOR2 (0x192)
+#define SPR_BOOKE_IVOR3 (0x193)
+#define SPR_BOOKE_IVOR4 (0x194)
+#define SPR_BOOKE_IVOR5 (0x195)
+#define SPR_BOOKE_IVOR6 (0x196)
+#define SPR_BOOKE_IVOR7 (0x197)
+#define SPR_BOOKE_IVOR8 (0x198)
+#define SPR_BOOKE_IVOR9 (0x199)
+#define SPR_BOOKE_IVOR10 (0x19A)
+#define SPR_BOOKE_IVOR11 (0x19B)
+#define SPR_BOOKE_IVOR12 (0x19C)
+#define SPR_BOOKE_IVOR13 (0x19D)
+#define SPR_BOOKE_IVOR14 (0x19E)
+#define SPR_BOOKE_IVOR15 (0x19F)
+#define SPR_E500_SPEFSCR (0x200)
+#define SPR_E500_BBEAR (0x201)
+#define SPR_E500_BBTAR (0x202)
+#define SPR_BOOKE_ATBL (0x20E)
+#define SPR_BOOKE_ATBU (0x20F)
+#define SPR_IBAT0U (0x210)
+#define SPR_BOOKE_IVOR32 (0x210)
+#define SPR_IBAT0L (0x211)
+#define SPR_BOOKE_IVOR33 (0x211)
+#define SPR_IBAT1U (0x212)
+#define SPR_BOOKE_IVOR34 (0x212)
+#define SPR_IBAT1L (0x213)
+#define SPR_BOOKE_IVOR35 (0x213)
+#define SPR_IBAT2U (0x214)
+#define SPR_BOOKE_IVOR36 (0x214)
+#define SPR_IBAT2L (0x215)
+#define SPR_E500_L1CFG0 (0x215)
+#define SPR_BOOKE_IVOR37 (0x215)
+#define SPR_IBAT3U (0x216)
+#define SPR_E500_L1CFG1 (0x216)
+#define SPR_IBAT3L (0x217)
+#define SPR_DBAT0U (0x218)
+#define SPR_DBAT0L (0x219)
+#define SPR_DBAT1U (0x21A)
+#define SPR_DBAT1L (0x21B)
+#define SPR_DBAT2U (0x21C)
+#define SPR_DBAT2L (0x21D)
+#define SPR_DBAT3U (0x21E)
+#define SPR_DBAT3L (0x21F)
+#define SPR_IBAT4U (0x230)
+#define SPR_IBAT4L (0x231)
+#define SPR_IBAT5U (0x232)
+#define SPR_IBAT5L (0x233)
+#define SPR_IBAT6U (0x234)
+#define SPR_IBAT6L (0x235)
+#define SPR_IBAT7U (0x236)
+#define SPR_IBAT7L (0x237)
+#define SPR_DBAT4U (0x238)
+#define SPR_DBAT4L (0x239)
+#define SPR_DBAT5U (0x23A)
+#define SPR_BOOKE_MCSRR0 (0x23A)
+#define SPR_DBAT5L (0x23B)
+#define SPR_BOOKE_MCSRR1 (0x23B)
+#define SPR_DBAT6U (0x23C)
+#define SPR_BOOKE_MCSR (0x23C)
+#define SPR_DBAT6L (0x23D)
+#define SPR_E500_MCAR (0x23D)
+#define SPR_DBAT7U (0x23E)
+#define SPR_BOOKE_DSRR0 (0x23E)
+#define SPR_DBAT7L (0x23F)
+#define SPR_BOOKE_DSRR1 (0x23F)
+#define SPR_BOOKE_SPRG8 (0x25C)
+#define SPR_BOOKE_SPRG9 (0x25D)
+#define SPR_BOOKE_MAS0 (0x270)
+#define SPR_BOOKE_MAS1 (0x271)
+#define SPR_BOOKE_MAS2 (0x272)
+#define SPR_BOOKE_MAS3 (0x273)
+#define SPR_BOOKE_MAS4 (0x274)
+#define SPR_BOOKE_MAS6 (0x276)
+#define SPR_BOOKE_PID1 (0x279)
+#define SPR_BOOKE_PID2 (0x27A)
+#define SPR_BOOKE_TLB0CFG (0x2B0)
+#define SPR_BOOKE_TLB1CFG (0x2B1)
+#define SPR_BOOKE_TLB2CFG (0x2B2)
+#define SPR_BOOKE_TLB3CFG (0x2B3)
+#define SPR_BOOKE_EPR (0x2BE)
+#define SPR_440_INV0 (0x370)
+#define SPR_440_INV1 (0x371)
+#define SPR_440_INV2 (0x372)
+#define SPR_440_INV3 (0x373)
+#define SPR_440_IVT0 (0x374)
+#define SPR_440_IVT1 (0x375)
+#define SPR_440_IVT2 (0x376)
+#define SPR_440_IVT3 (0x377)
+#define SPR_440_DNV0 (0x390)
+#define SPR_440_DNV1 (0x391)
+#define SPR_440_DNV2 (0x392)
+#define SPR_440_DNV3 (0x393)
+#define SPR_440_DVT0 (0x394)
+#define SPR_440_DVT1 (0x395)
+#define SPR_440_DVT2 (0x396)
+#define SPR_440_DVT3 (0x397)
+#define SPR_440_DVLIM (0x398)
+#define SPR_440_IVLIM (0x399)
+#define SPR_440_RSTCFG (0x39B)
+#define SPR_BOOKE_DCBTRL (0x39C)
+#define SPR_BOOKE_DCBTRH (0x39D)
+#define SPR_BOOKE_ICBTRL (0x39E)
+#define SPR_BOOKE_ICBTRH (0x39F)
+#define SPR_UMMCR0 (0x3A8)
+#define SPR_UPMC1 (0x3A9)
+#define SPR_UPMC2 (0x3AA)
+#define SPR_USIA (0x3AB)
+#define SPR_UMMCR1 (0x3AC)
+#define SPR_UPMC3 (0x3AD)
+#define SPR_UPMC4 (0x3AE)
+#define SPR_USDA (0x3AF)
+#define SPR_40x_ZPR (0x3B0)
+#define SPR_BOOKE_MAS7 (0x3B0)
+#define SPR_40x_PID (0x3B1)
+#define SPR_440_MMUCR (0x3B2)
+#define SPR_4xx_CCR0 (0x3B3)
+#define SPR_BOOKE_EPLC (0x3B3)
+#define SPR_405_IAC3 (0x3B4)
+#define SPR_BOOKE_EPSC (0x3B4)
+#define SPR_405_IAC4 (0x3B5)
+#define SPR_405_DVC1 (0x3B6)
+#define SPR_405_DVC2 (0x3B7)
+#define SPR_MMCR0 (0x3B8)
+#define SPR_PMC1 (0x3B9)
+#define SPR_40x_SGR (0x3B9)
+#define SPR_PMC2 (0x3BA)
+#define SPR_40x_DCWR (0x3BA)
+#define SPR_SIA (0x3BB)
+#define SPR_405_SLER (0x3BB)
+#define SPR_MMCR1 (0x3BC)
+#define SPR_405_SU0R (0x3BC)
+#define SPR_PMC3 (0x3BD)
+#define SPR_405_DBCR1 (0x3BD)
+#define SPR_PMC4 (0x3BE)
+#define SPR_SDA (0x3BF)
+#define SPR_403_VTBL (0x3CC)
+#define SPR_403_VTBU (0x3CD)
+#define SPR_DMISS (0x3D0)
+#define SPR_DCMP (0x3D1)
+#define SPR_HASH1 (0x3D2)
+#define SPR_HASH2 (0x3D3)
+#define SPR_BOOKE_ICBDR (0x3D3)
+#define SPR_IMISS (0x3D4)
+#define SPR_40x_ESR (0x3D4)
+#define SPR_ICMP (0x3D5)
+#define SPR_40x_DEAR (0x3D5)
+#define SPR_RPA (0x3D6)
+#define SPR_40x_EVPR (0x3D6)
+#define SPR_403_CDBCR (0x3D7)
+#define SPR_TCR (0x3D8)
+#define SPR_40x_TSR (0x3D8)
+#define SPR_IBR (0x3DA)
+#define SPR_40x_TCR (0x3DA)
+#define SPR_ESASR (0x3DB)
+#define SPR_40x_PIT (0x3DB)
+#define SPR_403_TBL (0x3DC)
+#define SPR_403_TBU (0x3DD)
+#define SPR_SEBR (0x3DE)
+#define SPR_40x_SRR2 (0x3DE)
+#define SPR_SER (0x3DF)
+#define SPR_40x_SRR3 (0x3DF)
+#define SPR_HID0 (0x3F0)
+#define SPR_40x_DBSR (0x3F0)
+#define SPR_HID1 (0x3F1)
+#define SPR_IABR (0x3F2)
+#define SPR_40x_DBCR0 (0x3F2)
+#define SPR_601_HID2 (0x3F2)
+#define SPR_E500_L1CSR0 (0x3F2)
+#define SPR_HID2 (0x3F3)
+#define SPR_E500_L1CSR1 (0x3F3)
+#define SPR_440_DBDR (0x3F3)
+#define SPR_40x_IAC1 (0x3F4)
+#define SPR_BOOKE_MMUCSR0 (0x3F4)
+#define SPR_DABR (0x3F5)
#define DABR_MASK (~(target_ulong)0x7)
-#define SPR_40x_IAC2 (0x3F5)
-#define SPR_601_HID5 (0x3F5)
-#define SPR_40x_DAC1 (0x3F6)
-#define SPR_40x_DAC2 (0x3F7)
-#define SPR_L2PM (0x3F8)
-#define SPR_750_HID2 (0x3F8)
-#define SPR_L2CR (0x3F9)
-#define SPR_IABR2 (0x3FA)
-#define SPR_40x_DCCR (0x3FA)
-#define SPR_ICTC (0x3FB)
-#define SPR_40x_ICCR (0x3FB)
-#define SPR_THRM1 (0x3FC)
-#define SPR_403_PBL1 (0x3FC)
-#define SPR_SP (0x3FD)
-#define SPR_THRM2 (0x3FD)
-#define SPR_403_PBU1 (0x3FD)
-#define SPR_LT (0x3FE)
-#define SPR_THRM3 (0x3FE)
-#define SPR_FPECR (0x3FE)
-#define SPR_403_PBL2 (0x3FE)
-#define SPR_PIR (0x3FF)
-#define SPR_403_PBU2 (0x3FF)
-#define SPR_601_HID15 (0x3FF)
+#define SPR_E500_BUCSR (0x3F5)
+#define SPR_40x_IAC2 (0x3F5)
+#define SPR_601_HID5 (0x3F5)
+#define SPR_40x_DAC1 (0x3F6)
+#define SPR_40x_DAC2 (0x3F7)
+#define SPR_BOOKE_MMUCFG (0x3F7)
+#define SPR_L2PM (0x3F8)
+#define SPR_750_HID2 (0x3F8)
+#define SPR_L2CR (0x3F9)
+#define SPR_IABR2 (0x3FA)
+#define SPR_40x_DCCR (0x3FA)
+#define SPR_ICTC (0x3FB)
+#define SPR_40x_ICCR (0x3FB)
+#define SPR_THRM1 (0x3FC)
+#define SPR_403_PBL1 (0x3FC)
+#define SPR_SP (0x3FD)
+#define SPR_THRM2 (0x3FD)
+#define SPR_403_PBU1 (0x3FD)
+#define SPR_LT (0x3FE)
+#define SPR_THRM3 (0x3FE)
+#define SPR_FPECR (0x3FE)
+#define SPR_403_PBL2 (0x3FE)
+#define SPR_PIR (0x3FF)
+#define SPR_403_PBU2 (0x3FF)
+#define SPR_601_HID15 (0x3FF)
+#define SPR_E500_SVR (0x3FF)
+/*****************************************************************************/
/* Memory access type :
* may be needed for precise access rights control and precise exceptions.
*/
@@ -974,11 +1292,13 @@
#define EXCP_970_MAINT 0x1600 /* Maintenance exception */
#define EXCP_970_THRM 0x1800 /* Thermal exception */
#define EXCP_970_VPUA 0x1700 /* VPU assist exception */
+/* SPE related exceptions */
+#define EXCP_NO_SPE 0x0F20 /* SPE unavailable exception */
/* End of exception vectors area */
#define EXCP_PPC_MAX 0x4000
/* Qemu exceptions: special cases we want to stop translation */
#define EXCP_MTMSR 0x11000 /* mtmsr instruction: */
- /* may change privilege level */
+ /* may change privilege level */
#define EXCP_BRANCH 0x11001 /* branch instruction */
#define EXCP_SYSCALL_USER 0x12000 /* System call in user mode only */
#define EXCP_INTERRUPT_CRITICAL 0x13000 /* critical IRQ */
@@ -1022,6 +1342,71 @@
EXCP_TRAP = 0x40,
};
+/* Hardware interruption sources:
+ * all those exception can be raised simulteaneously
+ */
+/* Input pins definitions */
+enum {
+ /* 6xx bus input pins */
+ PPC6xx_INPUT_HRESET = 0,
+ PPC6xx_INPUT_SRESET = 1,
+ PPC6xx_INPUT_CKSTP_IN = 2,
+ PPC6xx_INPUT_MCP = 3,
+ PPC6xx_INPUT_SMI = 4,
+ PPC6xx_INPUT_INT = 5,
+};
+
+enum {
+ /* Embedded PowerPC input pins */
+ PPCBookE_INPUT_HRESET = 0,
+ PPCBookE_INPUT_SRESET = 1,
+ PPCBookE_INPUT_CKSTP_IN = 2,
+ PPCBookE_INPUT_MCP = 3,
+ PPCBookE_INPUT_SMI = 4,
+ PPCBookE_INPUT_INT = 5,
+ PPCBookE_INPUT_CINT = 6,
+};
+
+enum {
+ /* PowerPC 405 input pins */
+ PPC405_INPUT_RESET_CORE = 0,
+ PPC405_INPUT_RESET_CHIP = 1,
+ PPC405_INPUT_RESET_SYS = 2,
+ PPC405_INPUT_CINT = 3,
+ PPC405_INPUT_INT = 4,
+ PPC405_INPUT_HALT = 5,
+ PPC405_INPUT_DEBUG = 6,
+};
+
+enum {
+ /* PowerPC 970 input pins */
+ PPC970_INPUT_HRESET = 0,
+ PPC970_INPUT_SRESET = 1,
+ PPC970_INPUT_CKSTP = 2,
+ PPC970_INPUT_TBEN = 3,
+ PPC970_INPUT_MCP = 4,
+ PPC970_INPUT_INT = 5,
+ PPC970_INPUT_THINT = 6,
+};
+
+/* Hardware exceptions definitions */
+enum {
+ /* External hardware exception sources */
+ PPC_INTERRUPT_RESET = 0, /* Reset exception */
+ PPC_INTERRUPT_MCK = 1, /* Machine check exception */
+ PPC_INTERRUPT_EXT = 2, /* External interrupt */
+ PPC_INTERRUPT_SMI = 3, /* System management interrupt */
+ PPC_INTERRUPT_CEXT = 4, /* Critical external interrupt */
+ PPC_INTERRUPT_DEBUG = 5, /* External debug exception */
+ PPC_INTERRUPT_THERM = 6, /* Thermal exception */
+ /* Internal hardware exception sources */
+ PPC_INTERRUPT_DECR = 7, /* Decrementer exception */
+ PPC_INTERRUPT_HDECR = 8, /* Hypervisor decrementer exception */
+ PPC_INTERRUPT_PIT = 9, /* Programmable inteval timer interrupt */
+ PPC_INTERRUPT_FIT = 10, /* Fixed interval timer interrupt */
+ PPC_INTERRUPT_WDT = 11, /* Watchdog timer interrupt */
+};
+
/*****************************************************************************/
#endif /* !defined (__CPU_PPC_H__) */
Modified: trunk/src/host/qemu-neo1973/target-ppc/exec.h
===================================================================
--- trunk/src/host/qemu-neo1973/target-ppc/exec.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/target-ppc/exec.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -1,7 +1,7 @@
/*
* PowerPC emulation definitions for qemu.
*
- * Copyright (c) 2003-2005 Jocelyn Mayer
+ * Copyright (c) 2003-2007 Jocelyn Mayer
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -24,15 +24,44 @@
#include "dyngen-exec.h"
-#define TARGET_LONG_BITS 32
+#include "cpu.h"
+#include "exec-all.h"
+/* For normal operations, precise emulation should not be needed */
+//#define USE_PRECISE_EMULATION 1
+#define USE_PRECISE_EMULATION 0
+
register struct CPUPPCState *env asm(AREG0);
-register uint32_t T0 asm(AREG1);
-register uint32_t T1 asm(AREG2);
-register uint32_t T2 asm(AREG3);
+#if TARGET_LONG_BITS > HOST_LONG_BITS
+/* no registers can be used */
+#define T0 (env->t0)
+#define T1 (env->t1)
+#define T2 (env->t2)
+#else
+register unsigned long T0 asm(AREG1);
+register unsigned long T1 asm(AREG2);
+register unsigned long T2 asm(AREG3);
+#endif
+/* We may, sometime, need 64 bits registers on 32 bits target */
+#if defined(TARGET_PPC64) || defined(TARGET_PPCEMB) || (HOST_LONG_BITS == 64)
+#define T0_64 T0
+#define T1_64 T1
+#define T2_64 T2
+#else
+/* no registers can be used */
+#define T0_64 (env->t0)
+#define T1_64 (env->t1)
+#define T2_64 (env->t2)
+#endif
+/* Provision for Altivec */
+#define T0_avr (env->t0_avr)
+#define T1_avr (env->t1_avr)
+#define T2_avr (env->t2_avr)
+/* XXX: to clean: remove this mess */
#define PARAM(n) ((uint32_t)PARAM##n)
#define SPARAM(n) ((int32_t)PARAM##n)
+
#define FT0 (env->ft0)
#define FT1 (env->ft1)
#define FT2 (env->ft2)
@@ -43,14 +72,28 @@
# define RETURN() __asm__ __volatile__("" : : : "memory");
#endif
-#include "cpu.h"
-#include "exec-all.h"
+static inline target_ulong rotl8 (target_ulong i, int n)
+{
+ return (((uint8_t)i << n) | ((uint8_t)i >> (8 - n)));
+}
-static inline uint32_t rotl (uint32_t i, int n)
+static inline target_ulong rotl16 (target_ulong i, int n)
{
- return ((i << n) | (i >> (32 - n)));
+ return (((uint16_t)i << n) | ((uint16_t)i >> (16 - n)));
}
+static inline target_ulong rotl32 (target_ulong i, int n)
+{
+ return (((uint32_t)i << n) | ((uint32_t)i >> (32 - n)));
+}
+
+#if defined(TARGET_PPC64)
+static inline target_ulong rotl64 (target_ulong i, int n)
+{
+ return (((uint64_t)i << n) | ((uint64_t)i >> (64 - n)));
+}
+#endif
+
#if !defined(CONFIG_USER_ONLY)
#include "softmmu_exec.h"
#endif /* !defined(CONFIG_USER_ONLY) */
@@ -58,24 +101,16 @@
void do_raise_exception_err (uint32_t exception, int error_code);
void do_raise_exception (uint32_t exception);
-void do_sraw(void);
+int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong vaddr,
+ int rw, int access_type, int check_BATs);
-void do_fctiw (void);
-void do_fctiwz (void);
-void do_fnmadd (void);
-void do_fnmsub (void);
-void do_fsqrt (void);
-void do_fres (void);
-void do_frsqrte (void);
-void do_fsel (void);
-void do_fcmpu (void);
-void do_fcmpo (void);
+void ppc6xx_tlb_invalidate_all (CPUState *env);
+void ppc6xx_tlb_invalidate_virt (CPUState *env, target_ulong eaddr,
+ int is_code);
+void ppc6xx_tlb_store (CPUState *env, target_ulong EPN, int way, int is_code,
+ target_ulong pte0, target_ulong pte1);
+void ppc4xx_tlb_invalidate_all (CPUState *env);
-void do_check_reservation (void);
-void do_icbi (void);
-void do_tlbia (void);
-void do_tlbie (void);
-
static inline void env_to_regs(void)
{
}
@@ -84,7 +119,7 @@
{
}
-int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
+int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
int is_user, int is_softmmu);
#endif /* !defined (__PPC_H__) */
Modified: trunk/src/host/qemu-neo1973/target-ppc/helper.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-ppc/helper.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/target-ppc/helper.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -1,7 +1,7 @@
/*
* PowerPC emulation helpers for qemu.
*
- * Copyright (c) 2003-2005 Jocelyn Mayer
+ * Copyright (c) 2003-2007 Jocelyn Mayer
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -30,18 +30,19 @@
//#define DEBUG_MMU
//#define DEBUG_BATS
+//#define DEBUG_SOFTWARE_TLB
//#define DEBUG_EXCEPTIONS
//#define FLUSH_ALL_TLBS
/*****************************************************************************/
/* PowerPC MMU emulation */
-#if defined(CONFIG_USER_ONLY)
-int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
+#if defined(CONFIG_USER_ONLY)
+int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
int is_user, int is_softmmu)
{
int exception, error_code;
-
+
if (rw == 2) {
exception = EXCP_ISI;
error_code = 0;
@@ -55,26 +56,306 @@
}
env->exception_index = exception;
env->error_code = error_code;
+
return 1;
}
-target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
+
+target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr)
{
return addr;
}
#else
+/* Common routines used by software and hardware TLBs emulation */
+static inline int pte_is_valid (target_ulong pte0)
+{
+ return pte0 & 0x80000000 ? 1 : 0;
+}
+
+static inline void pte_invalidate (target_ulong *pte0)
+{
+ *pte0 &= ~0x80000000;
+}
+
+#define PTE_PTEM_MASK 0x7FFFFFBF
+#define PTE_CHECK_MASK (TARGET_PAGE_MASK | 0x7B)
+
+static int pte_check (mmu_ctx_t *ctx,
+ target_ulong pte0, target_ulong pte1, int h, int rw)
+{
+ int access, ret;
+
+ access = 0;
+ ret = -1;
+ /* Check validity and table match */
+ if (pte_is_valid(pte0) && (h == ((pte0 >> 6) & 1))) {
+ /* Check vsid & api */
+ if ((pte0 & PTE_PTEM_MASK) == ctx->ptem) {
+ if (ctx->raddr != (target_ulong)-1) {
+ /* all matches should have equal RPN, WIMG & PP */
+ if ((ctx->raddr & PTE_CHECK_MASK) != (pte1 & PTE_CHECK_MASK)) {
+ if (loglevel > 0)
+ fprintf(logfile, "Bad RPN/WIMG/PP\n");
+ return -3;
+ }
+ }
+ /* Compute access rights */
+ if (ctx->key == 0) {
+ access = PAGE_READ;
+ if ((pte1 & 0x00000003) != 0x3)
+ access |= PAGE_WRITE;
+ } else {
+ switch (pte1 & 0x00000003) {
+ case 0x0:
+ access = 0;
+ break;
+ case 0x1:
+ case 0x3:
+ access = PAGE_READ;
+ break;
+ case 0x2:
+ access = PAGE_READ | PAGE_WRITE;
+ break;
+ }
+ }
+ /* Keep the matching PTE informations */
+ ctx->raddr = pte1;
+ ctx->prot = access;
+ if ((rw == 0 && (access & PAGE_READ)) ||
+ (rw == 1 && (access & PAGE_WRITE))) {
+ /* Access granted */
+#if defined (DEBUG_MMU)
+ if (loglevel != 0)
+ fprintf(logfile, "PTE access granted !\n");
+#endif
+ ret = 0;
+ } else {
+ /* Access right violation */
+#if defined (DEBUG_MMU)
+ if (loglevel != 0)
+ fprintf(logfile, "PTE access rejected\n");
+#endif
+ ret = -2;
+ }
+ }
+ }
+
+ return ret;
+}
+
+static int pte_update_flags (mmu_ctx_t *ctx, target_ulong *pte1p,
+ int ret, int rw)
+{
+ int store = 0;
+
+ /* Update page flags */
+ if (!(*pte1p & 0x00000100)) {
+ /* Update accessed flag */
+ *pte1p |= 0x00000100;
+ store = 1;
+ }
+ if (!(*pte1p & 0x00000080)) {
+ if (rw == 1 && ret == 0) {
+ /* Update changed flag */
+ *pte1p |= 0x00000080;
+ store = 1;
+ } else {
+ /* Force page fault for first write access */
+ ctx->prot &= ~PAGE_WRITE;
+ }
+ }
+
+ return store;
+}
+
+/* Software driven TLB helpers */
+static int ppc6xx_tlb_getnum (CPUState *env, target_ulong eaddr,
+ int way, int is_code)
+{
+ int nr;
+
+ /* Select TLB num in a way from address */
+ nr = (eaddr >> TARGET_PAGE_BITS) & (env->tlb_per_way - 1);
+ /* Select TLB way */
+ nr += env->tlb_per_way * way;
+ /* 6xx have separate TLBs for instructions and data */
+ if (is_code && env->id_tlbs == 1)
+ nr += env->nb_tlb;
+
+ return nr;
+}
+
+void ppc6xx_tlb_invalidate_all (CPUState *env)
+{
+ ppc6xx_tlb_t *tlb;
+ int nr, max;
+
+#if defined (DEBUG_SOFTWARE_TLB) && 0
+ if (loglevel != 0) {
+ fprintf(logfile, "Invalidate all TLBs\n");
+ }
+#endif
+ /* Invalidate all defined software TLB */
+ max = env->nb_tlb;
+ if (env->id_tlbs == 1)
+ max *= 2;
+ for (nr = 0; nr < max; nr++) {
+ tlb = &env->tlb[nr].tlb6;
+#if !defined(FLUSH_ALL_TLBS)
+ tlb_flush_page(env, tlb->EPN);
+#endif
+ pte_invalidate(&tlb->pte0);
+ }
+#if defined(FLUSH_ALL_TLBS)
+ tlb_flush(env, 1);
+#endif
+}
+
+static inline void __ppc6xx_tlb_invalidate_virt (CPUState *env,
+ target_ulong eaddr,
+ int is_code, int match_epn)
+{
+#if !defined(FLUSH_ALL_TLBS)
+ ppc6xx_tlb_t *tlb;
+ int way, nr;
+
+ /* Invalidate ITLB + DTLB, all ways */
+ for (way = 0; way < env->nb_ways; way++) {
+ nr = ppc6xx_tlb_getnum(env, eaddr, way, is_code);
+ tlb = &env->tlb[nr].tlb6;
+ if (pte_is_valid(tlb->pte0) && (match_epn == 0 || eaddr == tlb->EPN)) {
+#if defined (DEBUG_SOFTWARE_TLB)
+ if (loglevel != 0) {
+ fprintf(logfile, "TLB invalidate %d/%d " ADDRX "\n",
+ nr, env->nb_tlb, eaddr);
+ }
+#endif
+ pte_invalidate(&tlb->pte0);
+ tlb_flush_page(env, tlb->EPN);
+ }
+ }
+#else
+ /* XXX: PowerPC specification say this is valid as well */
+ ppc6xx_tlb_invalidate_all(env);
+#endif
+}
+
+void ppc6xx_tlb_invalidate_virt (CPUState *env, target_ulong eaddr,
+ int is_code)
+{
+ __ppc6xx_tlb_invalidate_virt(env, eaddr, is_code, 0);
+}
+
+void ppc6xx_tlb_store (CPUState *env, target_ulong EPN, int way, int is_code,
+ target_ulong pte0, target_ulong pte1)
+{
+ ppc6xx_tlb_t *tlb;
+ int nr;
+
+ nr = ppc6xx_tlb_getnum(env, EPN, way, is_code);
+ tlb = &env->tlb[nr].tlb6;
+#if defined (DEBUG_SOFTWARE_TLB)
+ if (loglevel != 0) {
+ fprintf(logfile, "Set TLB %d/%d EPN " ADDRX " PTE0 " ADDRX
+ " PTE1 " ADDRX "\n", nr, env->nb_tlb, EPN, pte0, pte1);
+ }
+#endif
+ /* Invalidate any pending reference in Qemu for this virtual address */
+ __ppc6xx_tlb_invalidate_virt(env, EPN, is_code, 1);
+ tlb->pte0 = pte0;
+ tlb->pte1 = pte1;
+ tlb->EPN = EPN;
+ /* Store last way for LRU mechanism */
+ env->last_way = way;
+}
+
+static int ppc6xx_tlb_check (CPUState *env, mmu_ctx_t *ctx,
+ target_ulong eaddr, int rw, int access_type)
+{
+ ppc6xx_tlb_t *tlb;
+ int nr, best, way;
+ int ret;
+
+ best = -1;
+ ret = -1; /* No TLB found */
+ for (way = 0; way < env->nb_ways; way++) {
+ nr = ppc6xx_tlb_getnum(env, eaddr, way,
+ access_type == ACCESS_CODE ? 1 : 0);
+ tlb = &env->tlb[nr].tlb6;
+ /* This test "emulates" the PTE index match for hardware TLBs */
+ if ((eaddr & TARGET_PAGE_MASK) != tlb->EPN) {
+#if defined (DEBUG_SOFTWARE_TLB)
+ if (loglevel != 0) {
+ fprintf(logfile, "TLB %d/%d %s [" ADDRX " " ADDRX
+ "] <> " ADDRX "\n",
+ nr, env->nb_tlb,
+ pte_is_valid(tlb->pte0) ? "valid" : "inval",
+ tlb->EPN, tlb->EPN + TARGET_PAGE_SIZE, eaddr);
+ }
+#endif
+ continue;
+ }
+#if defined (DEBUG_SOFTWARE_TLB)
+ if (loglevel != 0) {
+ fprintf(logfile, "TLB %d/%d %s " ADDRX " <> " ADDRX " " ADDRX
+ " %c %c\n",
+ nr, env->nb_tlb,
+ pte_is_valid(tlb->pte0) ? "valid" : "inval",
+ tlb->EPN, eaddr, tlb->pte1,
+ rw ? 'S' : 'L', access_type == ACCESS_CODE ? 'I' : 'D');
+ }
+#endif
+ switch (pte_check(ctx, tlb->pte0, tlb->pte1, 0, rw)) {
+ case -3:
+ /* TLB inconsistency */
+ return -1;
+ case -2:
+ /* Access violation */
+ ret = -2;
+ best = nr;
+ break;
+ case -1:
+ default:
+ /* No match */
+ break;
+ case 0:
+ /* access granted */
+ /* XXX: we should go on looping to check all TLBs consistency
+ * but we can speed-up the whole thing as the
+ * result would be undefined if TLBs are not consistent.
+ */
+ ret = 0;
+ best = nr;
+ goto done;
+ }
+ }
+ if (best != -1) {
+ done:
+#if defined (DEBUG_SOFTWARE_TLB)
+ if (loglevel != 0) {
+ fprintf(logfile, "found TLB at addr 0x%08lx prot=0x%01x ret=%d\n",
+ ctx->raddr & TARGET_PAGE_MASK, ctx->prot, ret);
+ }
+#endif
+ /* Update page flags */
+ pte_update_flags(ctx, &env->tlb[best].tlb6.pte1, ret, rw);
+ }
+
+ return ret;
+}
+
/* Perform BAT hit & translation */
-static int get_bat (CPUState *env, uint32_t *real, int *prot,
- uint32_t virtual, int rw, int type)
+static int get_bat (CPUState *env, mmu_ctx_t *ctx,
+ target_ulong virtual, int rw, int type)
{
- uint32_t *BATlt, *BATut, *BATu, *BATl;
- uint32_t base, BEPIl, BEPIu, bl;
+ target_ulong *BATlt, *BATut, *BATu, *BATl;
+ target_ulong base, BEPIl, BEPIu, bl;
int i;
int ret = -1;
#if defined (DEBUG_BATS)
- if (loglevel > 0) {
- fprintf(logfile, "%s: %cBAT v 0x%08x\n", __func__,
- type == ACCESS_CODE ? 'I' : 'D', virtual);
+ if (loglevel != 0) {
+ fprintf(logfile, "%s: %cBAT v 0x" ADDRX "\n", __func__,
+ type == ACCESS_CODE ? 'I' : 'D', virtual);
}
#endif
switch (type) {
@@ -88,9 +369,9 @@
break;
}
#if defined (DEBUG_BATS)
- if (loglevel > 0) {
- fprintf(logfile, "%s...: %cBAT v 0x%08x\n", __func__,
- type == ACCESS_CODE ? 'I' : 'D', virtual);
+ if (loglevel != 0) {
+ fprintf(logfile, "%s...: %cBAT v 0x" ADDRX "\n", __func__,
+ type == ACCESS_CODE ? 'I' : 'D', virtual);
}
#endif
base = virtual & 0xFFFC0000;
@@ -101,8 +382,9 @@
BEPIl = *BATu & 0x0FFE0000;
bl = (*BATu & 0x00001FFC) << 15;
#if defined (DEBUG_BATS)
- if (loglevel > 0) {
- fprintf(logfile, "%s: %cBAT%d v 0x%08x BATu 0x%08x BATl 0x%08x\n",
+ if (loglevel != 0) {
+ fprintf(logfile, "%s: %cBAT%d v 0x" ADDRX " BATu 0x" ADDRX
+ " BATl 0x" ADDRX "\n",
__func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual,
*BATu, *BATl);
}
@@ -113,18 +395,19 @@
if ((msr_pr == 0 && (*BATu & 0x00000002)) ||
(msr_pr == 1 && (*BATu & 0x00000001))) {
/* Get physical address */
- *real = (*BATl & 0xF0000000) |
+ ctx->raddr = (*BATl & 0xF0000000) |
((virtual & 0x0FFE0000 & bl) | (*BATl & 0x0FFE0000)) |
(virtual & 0x0001F000);
if (*BATl & 0x00000001)
- *prot = PAGE_READ;
+ ctx->prot = PAGE_READ;
if (*BATl & 0x00000002)
- *prot = PAGE_WRITE | PAGE_READ;
+ ctx->prot = PAGE_WRITE | PAGE_READ;
#if defined (DEBUG_BATS)
- if (loglevel > 0) {
- fprintf(logfile, "BAT %d match: r 0x%08x prot=%c%c\n",
- i, *real, *prot & PAGE_READ ? 'R' : '-',
- *prot & PAGE_WRITE ? 'W' : '-');
+ if (loglevel != 0) {
+ fprintf(logfile, "BAT %d match: r 0x" PADDRX
+ " prot=%c%c\n",
+ i, ctx->raddr, ctx->prot & PAGE_READ ? 'R' : '-',
+ ctx->prot & PAGE_WRITE ? 'W' : '-');
}
#endif
ret = 0;
@@ -134,17 +417,20 @@
}
if (ret < 0) {
#if defined (DEBUG_BATS)
- printf("no BAT match for 0x%08x:\n", virtual);
- for (i = 0; i < 4; i++) {
- BATu = &BATut[i];
- BATl = &BATlt[i];
- BEPIu = *BATu & 0xF0000000;
- BEPIl = *BATu & 0x0FFE0000;
- bl = (*BATu & 0x00001FFC) << 15;
- printf("%s: %cBAT%d v 0x%08x BATu 0x%08x BATl 0x%08x \n\t"
- "0x%08x 0x%08x 0x%08x\n",
- __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual,
- *BATu, *BATl, BEPIu, BEPIl, bl);
+ if (loglevel != 0) {
+ fprintf(logfile, "no BAT match for 0x" ADDRX ":\n", virtual);
+ for (i = 0; i < 4; i++) {
+ BATu = &BATut[i];
+ BATl = &BATlt[i];
+ BEPIu = *BATu & 0xF0000000;
+ BEPIl = *BATu & 0x0FFE0000;
+ bl = (*BATu & 0x00001FFC) << 15;
+ fprintf(logfile, "%s: %cBAT%d v 0x" ADDRX " BATu 0x" ADDRX
+ " BATl 0x" ADDRX " \n\t"
+ "0x" ADDRX " 0x" ADDRX " 0x" ADDRX "\n",
+ __func__, type == ACCESS_CODE ? 'I' : 'D', i, virtual,
+ *BATu, *BATl, BEPIu, BEPIl, bl);
+ }
}
#endif
}
@@ -153,189 +439,156 @@
}
/* PTE table lookup */
-static int find_pte (uint32_t *RPN, int *prot, uint32_t base, uint32_t va,
- int h, int key, int rw)
+static int find_pte (mmu_ctx_t *ctx, int h, int rw)
{
- uint32_t pte0, pte1, keep = 0, access = 0;
- int i, good = -1, store = 0;
- int ret = -1; /* No entry found */
+ target_ulong base, pte0, pte1;
+ int i, good = -1;
+ int ret;
+ ret = -1; /* No entry found */
+ base = ctx->pg_addr[h];
for (i = 0; i < 8; i++) {
pte0 = ldl_phys(base + (i * 8));
pte1 = ldl_phys(base + (i * 8) + 4);
#if defined (DEBUG_MMU)
if (loglevel > 0) {
- fprintf(logfile, "Load pte from 0x%08x => 0x%08x 0x%08x "
- "%d %d %d 0x%08x\n", base + (i * 8), pte0, pte1,
- pte0 >> 31, h, (pte0 >> 6) & 1, va);
- }
+ fprintf(logfile, "Load pte from 0x" ADDRX " => 0x" ADDRX
+ " 0x" ADDRX " %d %d %d 0x" ADDRX "\n",
+ base + (i * 8), pte0, pte1,
+ pte0 >> 31, h, (pte0 >> 6) & 1, ctx->ptem);
+ }
#endif
- /* Check validity and table match */
- if (pte0 & 0x80000000 && (h == ((pte0 >> 6) & 1))) {
- /* Check vsid & api */
- if ((pte0 & 0x7FFFFFBF) == va) {
- if (good == -1) {
- good = i;
- keep = pte1;
- } else {
- /* All matches should have equal RPN, WIMG & PP */
- if ((keep & 0xFFFFF07B) != (pte1 & 0xFFFFF07B)) {
- if (loglevel > 0)
- fprintf(logfile, "Bad RPN/WIMG/PP\n");
- return -1;
- }
- }
- /* Check access rights */
- if (key == 0) {
- access = PAGE_READ;
- if ((pte1 & 0x00000003) != 0x3)
- access |= PAGE_WRITE;
- } else {
- switch (pte1 & 0x00000003) {
- case 0x0:
- access = 0;
- break;
- case 0x1:
- case 0x3:
- access = PAGE_READ;
- break;
- case 0x2:
- access = PAGE_READ | PAGE_WRITE;
- break;
- }
- }
- if (ret < 0) {
- if ((rw == 0 && (access & PAGE_READ)) ||
- (rw == 1 && (access & PAGE_WRITE))) {
-#if defined (DEBUG_MMU)
- if (loglevel > 0)
- fprintf(logfile, "PTE access granted !\n");
-#endif
- good = i;
- keep = pte1;
- ret = 0;
- } else {
- /* Access right violation */
- ret = -2;
-#if defined (DEBUG_MMU)
- if (loglevel > 0)
- fprintf(logfile, "PTE access rejected\n");
-#endif
- }
- *prot = access;
- }
- }
+ switch (pte_check(ctx, pte0, pte1, h, rw)) {
+ case -3:
+ /* PTE inconsistency */
+ return -1;
+ case -2:
+ /* Access violation */
+ ret = -2;
+ good = i;
+ break;
+ case -1:
+ default:
+ /* No PTE match */
+ break;
+ case 0:
+ /* access granted */
+ /* XXX: we should go on looping to check all PTEs consistency
+ * but if we can speed-up the whole thing as the
+ * result would be undefined if PTEs are not consistent.
+ */
+ ret = 0;
+ good = i;
+ goto done;
}
}
if (good != -1) {
- *RPN = keep & 0xFFFFF000;
+ done:
#if defined (DEBUG_MMU)
- if (loglevel > 0) {
- fprintf(logfile, "found PTE at addr 0x%08x prot=0x%01x ret=%d\n",
- *RPN, *prot, ret);
- }
+ if (loglevel != 0) {
+ fprintf(logfile, "found PTE at addr 0x" PADDRX " prot=0x%01x "
+ "ret=%d\n",
+ ctx->raddr, ctx->prot, ret);
+ }
#endif
/* Update page flags */
- if (!(keep & 0x00000100)) {
- /* Access flag */
- keep |= 0x00000100;
- store = 1;
- }
- if (!(keep & 0x00000080)) {
- if (rw && ret == 0) {
- /* Change flag */
- keep |= 0x00000080;
- store = 1;
- } else {
- /* Force page fault for first write access */
- *prot &= ~PAGE_WRITE;
- }
- }
- if (store) {
- stl_phys_notdirty(base + (good * 8) + 4, keep);
- }
+ pte1 = ctx->raddr;
+ if (pte_update_flags(ctx, &pte1, ret, rw) == 1)
+ stl_phys_notdirty(base + (good * 8) + 4, pte1);
}
return ret;
}
-static inline uint32_t get_pgaddr (uint32_t sdr1, uint32_t hash, uint32_t mask)
+static inline target_phys_addr_t get_pgaddr (target_phys_addr_t sdr1,
+ target_phys_addr_t hash,
+ target_phys_addr_t mask)
{
return (sdr1 & 0xFFFF0000) | (hash & mask);
}
/* Perform segment based translation */
-static int get_segment (CPUState *env, uint32_t *real, int *prot,
- uint32_t virtual, int rw, int type)
+static int get_segment (CPUState *env, mmu_ctx_t *ctx,
+ target_ulong eaddr, int rw, int type)
{
- uint32_t pg_addr, sdr, ptem, vsid, pgidx;
- uint32_t hash, mask;
- uint32_t sr;
- int key;
+ target_phys_addr_t sdr, hash, mask;
+ target_ulong sr, vsid, pgidx;
int ret = -1, ret2;
- sr = env->sr[virtual >> 28];
+ sr = env->sr[eaddr >> 28];
#if defined (DEBUG_MMU)
if (loglevel > 0) {
- fprintf(logfile, "Check segment v=0x%08x %d 0x%08x nip=0x%08x "
- "lr=0x%08x ir=%d dr=%d pr=%d %d t=%d\n",
- virtual, virtual >> 28, sr, env->nip,
- env->lr, msr_ir, msr_dr, msr_pr, rw, type);
+ fprintf(logfile, "Check segment v=0x" ADDRX " %d 0x" ADDRX " nip=0x"
+ ADDRX " lr=0x" ADDRX " ir=%d dr=%d pr=%d %d t=%d\n",
+ eaddr, eaddr >> 28, sr, env->nip,
+ env->lr, msr_ir, msr_dr, msr_pr, rw, type);
}
#endif
- key = (((sr & 0x20000000) && msr_pr == 1) ||
- ((sr & 0x40000000) && msr_pr == 0)) ? 1 : 0;
+ ctx->key = (((sr & 0x20000000) && msr_pr == 1) ||
+ ((sr & 0x40000000) && msr_pr == 0)) ? 1 : 0;
if ((sr & 0x80000000) == 0) {
#if defined (DEBUG_MMU)
- if (loglevel > 0)
- fprintf(logfile, "pte segment: key=%d n=0x%08x\n",
- key, sr & 0x10000000);
+ if (loglevel > 0)
+ fprintf(logfile, "pte segment: key=%d n=0x" ADDRX "\n",
+ ctx->key, sr & 0x10000000);
#endif
/* Check if instruction fetch is allowed, if needed */
if (type != ACCESS_CODE || (sr & 0x10000000) == 0) {
/* Page address translation */
+ pgidx = (eaddr >> TARGET_PAGE_BITS) & 0xFFFF;
vsid = sr & 0x00FFFFFF;
- pgidx = (virtual >> 12) & 0xFFFF;
+ hash = ((vsid ^ pgidx) & 0x0007FFFF) << 6;
+ /* Primary table address */
sdr = env->sdr1;
- hash = ((vsid ^ pgidx) & 0x0007FFFF) << 6;
mask = ((sdr & 0x000001FF) << 16) | 0xFFC0;
- pg_addr = get_pgaddr(sdr, hash, mask);
- ptem = (vsid << 7) | (pgidx >> 10);
+ ctx->pg_addr[0] = get_pgaddr(sdr, hash, mask);
+ /* Secondary table address */
+ hash = (~hash) & 0x01FFFFC0;
+ ctx->pg_addr[1] = get_pgaddr(sdr, hash, mask);
+ ctx->ptem = (vsid << 7) | (pgidx >> 10);
+ /* Initialize real address with an invalid value */
+ ctx->raddr = (target_ulong)-1;
+ if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_6xx)) {
+ /* Software TLB search */
+ ret = ppc6xx_tlb_check(env, ctx, eaddr, rw, type);
+ } else {
#if defined (DEBUG_MMU)
- if (loglevel > 0) {
- fprintf(logfile, "0 sdr1=0x%08x vsid=0x%06x api=0x%04x "
- "hash=0x%07x pg_addr=0x%08x\n", sdr, vsid, pgidx, hash,
- pg_addr);
- }
+ if (loglevel != 0) {
+ fprintf(logfile, "0 sdr1=0x" PADDRX " vsid=0x%06x "
+ "api=0x%04x hash=0x%07x pg_addr=0x" PADDRX "\n",
+ sdr, (uint32_t)vsid, (uint32_t)pgidx,
+ (uint32_t)hash, ctx->pg_addr[0]);
+ }
#endif
- /* Primary table lookup */
- ret = find_pte(real, prot, pg_addr, ptem, 0, key, rw);
- if (ret < 0) {
- /* Secondary table lookup */
- hash = (~hash) & 0x01FFFFC0;
- pg_addr = get_pgaddr(sdr, hash, mask);
+ /* Primary table lookup */
+ ret = find_pte(ctx, 0, rw);
+ if (ret < 0) {
+ /* Secondary table lookup */
#if defined (DEBUG_MMU)
- if (virtual != 0xEFFFFFFF && loglevel > 0) {
- fprintf(logfile, "1 sdr1=0x%08x vsid=0x%06x api=0x%04x "
- "hash=0x%05x pg_addr=0x%08x\n", sdr, vsid, pgidx,
- hash, pg_addr);
- }
+ if (eaddr != 0xEFFFFFFF && loglevel != 0) {
+ fprintf(logfile,
+ "1 sdr1=0x" PADDRX " vsid=0x%06x api=0x%04x "
+ "hash=0x%05x pg_addr=0x" PADDRX "\n",
+ sdr, (uint32_t)vsid, (uint32_t)pgidx,
+ (uint32_t)hash, ctx->pg_addr[1]);
+ }
#endif
- ret2 = find_pte(real, prot, pg_addr, ptem, 1, key, rw);
- if (ret2 != -1)
- ret = ret2;
+ ret2 = find_pte(ctx, 1, rw);
+ if (ret2 != -1)
+ ret = ret2;
+ }
}
} else {
#if defined (DEBUG_MMU)
- if (loglevel > 0)
- fprintf(logfile, "No access allowed\n");
+ if (loglevel != 0)
+ fprintf(logfile, "No access allowed\n");
#endif
- ret = -3;
+ ret = -3;
}
} else {
#if defined (DEBUG_MMU)
- if (loglevel > 0)
- fprintf(logfile, "direct store...\n");
+ if (loglevel != 0)
+ fprintf(logfile, "direct store...\n");
#endif
/* Direct-store segment : absolutely *BUGGY* for now */
switch (type) {
@@ -356,7 +609,7 @@
/* Should make the instruction do no-op.
* As it already do no-op, it's quite easy :-)
*/
- *real = virtual;
+ ctx->raddr = eaddr;
return 0;
case ACCESS_EXT:
/* eciwx or ecowx */
@@ -366,12 +619,10 @@
fprintf(logfile, "ERROR: instruction should not need "
"address translation\n");
}
- printf("ERROR: instruction should not need "
- "address translation\n");
return -4;
}
- if ((rw == 1 || key != 1) && (rw == 0 || key != 0)) {
- *real = virtual;
+ if ((rw == 1 || ctx->key != 1) && (rw == 0 || ctx->key != 0)) {
+ ctx->raddr = eaddr;
ret = 2;
} else {
ret = -2;
@@ -381,54 +632,309 @@
return ret;
}
-static int get_physical_address (CPUState *env, uint32_t *physical, int *prot,
- uint32_t address, int rw, int access_type)
+/* Generic TLB check function for embedded PowerPC implementations */
+static int ppcemb_tlb_check (CPUState *env, ppcemb_tlb_t *tlb,
+ target_phys_addr_t *raddrp,
+ target_ulong address, int i)
{
+ target_ulong mask;
+
+ /* Check valid flag */
+ if (!(tlb->prot & PAGE_VALID)) {
+ if (loglevel != 0)
+ fprintf(logfile, "%s: TLB %d not valid\n", __func__, i);
+ return -1;
+ }
+ mask = ~(tlb->size - 1);
+ if (loglevel != 0) {
+ fprintf(logfile, "%s: TLB %d address " ADDRX " PID %d <=> "
+ ADDRX " " ADDRX " %d\n",
+ __func__, i, address, (int)env->spr[SPR_40x_PID],
+ tlb->EPN, mask, (int)tlb->PID);
+ }
+ /* Check PID */
+ if (tlb->PID != 0 && tlb->PID != env->spr[SPR_40x_PID])
+ return -1;
+ /* Check effective address */
+ if ((address & mask) != tlb->EPN)
+ return -1;
+ *raddrp = (tlb->RPN & mask) | (address & ~mask);
+
+ return 0;
+}
+
+/* Generic TLB search function for PowerPC embedded implementations */
+int ppcemb_tlb_search (CPUState *env, target_ulong address)
+{
+ ppcemb_tlb_t *tlb;
+ target_phys_addr_t raddr;
+ int i, ret;
+
+ /* Default return value is no match */
+ ret = -1;
+ for (i = 0; i < 64; i++) {
+ tlb = &env->tlb[i].tlbe;
+ if (ppcemb_tlb_check(env, tlb, &raddr, address, i) == 0) {
+ ret = i;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+/* Helpers specific to PowerPC 40x implementations */
+void ppc4xx_tlb_invalidate_all (CPUState *env)
+{
+ ppcemb_tlb_t *tlb;
+ int i;
+
+ for (i = 0; i < env->nb_tlb; i++) {
+ tlb = &env->tlb[i].tlbe;
+ if (tlb->prot & PAGE_VALID) {
+#if 0 // XXX: TLB have variable sizes then we flush all Qemu TLB.
+ end = tlb->EPN + tlb->size;
+ for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
+ tlb_flush_page(env, page);
+#endif
+ tlb->prot &= ~PAGE_VALID;
+ }
+ }
+ tlb_flush(env, 1);
+}
+
+int mmu4xx_get_physical_address (CPUState *env, mmu_ctx_t *ctx,
+ target_ulong address, int rw, int access_type)
+{
+ ppcemb_tlb_t *tlb;
+ target_phys_addr_t raddr;
+ int i, ret, zsel, zpr;
+
+ ret = -1;
+ raddr = -1;
+ for (i = 0; i < env->nb_tlb; i++) {
+ tlb = &env->tlb[i].tlbe;
+ if (ppcemb_tlb_check(env, tlb, &raddr, address, i) < 0)
+ continue;
+ zsel = (tlb->attr >> 4) & 0xF;
+ zpr = (env->spr[SPR_40x_ZPR] >> (28 - (2 * zsel))) & 0x3;
+ if (loglevel != 0) {
+ fprintf(logfile, "%s: TLB %d zsel %d zpr %d rw %d attr %08x\n",
+ __func__, i, zsel, zpr, rw, tlb->attr);
+ }
+ if (access_type == ACCESS_CODE) {
+ /* Check execute enable bit */
+ switch (zpr) {
+ case 0x2:
+ if (msr_pr)
+ goto check_exec_perm;
+ goto exec_granted;
+ case 0x0:
+ if (msr_pr) {
+ ctx->prot = 0;
+ ret = -3;
+ break;
+ }
+ /* No break here */
+ case 0x1:
+ check_exec_perm:
+ /* Check from TLB entry */
+ if (!(tlb->prot & PAGE_EXEC)) {
+ ret = -3;
+ } else {
+ if (tlb->prot & PAGE_WRITE) {
+ ctx->prot = PAGE_READ | PAGE_WRITE;
+ } else {
+ ctx->prot = PAGE_READ;
+ }
+ ret = 0;
+ }
+ break;
+ case 0x3:
+ exec_granted:
+ /* All accesses granted */
+ ctx->prot = PAGE_READ | PAGE_WRITE;
+ ret = 0;
+ break;
+ }
+ } else {
+ switch (zpr) {
+ case 0x2:
+ if (msr_pr)
+ goto check_rw_perm;
+ goto rw_granted;
+ case 0x0:
+ if (msr_pr) {
+ ctx->prot = 0;
+ ret = -2;
+ break;
+ }
+ /* No break here */
+ case 0x1:
+ check_rw_perm:
+ /* Check from TLB entry */
+ /* Check write protection bit */
+ if (tlb->prot & PAGE_WRITE) {
+ ctx->prot = PAGE_READ | PAGE_WRITE;
+ ret = 0;
+ } else {
+ ctx->prot = PAGE_READ;
+ if (rw)
+ ret = -2;
+ else
+ ret = 0;
+ }
+ break;
+ case 0x3:
+ rw_granted:
+ /* All accesses granted */
+ ctx->prot = PAGE_READ | PAGE_WRITE;
+ ret = 0;
+ break;
+ }
+ }
+ if (ret >= 0) {
+ ctx->raddr = raddr;
+ if (loglevel != 0) {
+ fprintf(logfile, "%s: access granted " ADDRX " => " REGX
+ " %d %d\n", __func__, address, ctx->raddr, ctx->prot,
+ ret);
+ }
+ return 0;
+ }
+ }
+ if (loglevel != 0) {
+ fprintf(logfile, "%s: access refused " ADDRX " => " REGX
+ " %d %d\n", __func__, address, raddr, ctx->prot,
+ ret);
+ }
+
+ return ret;
+}
+
+void store_40x_sler (CPUPPCState *env, uint32_t val)
+{
+ /* XXX: TO BE FIXED */
+ if (val != 0x00000000) {
+ cpu_abort(env, "Little-endian regions are not supported by now\n");
+ }
+ env->spr[SPR_405_SLER] = val;
+}
+
+static int check_physical (CPUState *env, mmu_ctx_t *ctx,
+ target_ulong eaddr, int rw)
+{
+ int in_plb, ret;
+
+ ctx->raddr = eaddr;
+ ctx->prot = PAGE_READ;
+ ret = 0;
+ if (unlikely(msr_pe != 0 && PPC_MMU(env) == PPC_FLAGS_MMU_403)) {
+ /* 403 family add some particular protections,
+ * using PBL/PBU registers for accesses with no translation.
+ */
+ in_plb =
+ /* Check PLB validity */
+ (env->pb[0] < env->pb[1] &&
+ /* and address in plb area */
+ eaddr >= env->pb[0] && eaddr < env->pb[1]) ||
+ (env->pb[2] < env->pb[3] &&
+ eaddr >= env->pb[2] && eaddr < env->pb[3]) ? 1 : 0;
+ if (in_plb ^ msr_px) {
+ /* Access in protected area */
+ if (rw == 1) {
+ /* Access is not allowed */
+ ret = -2;
+ }
+ } else {
+ /* Read-write access is allowed */
+ ctx->prot |= PAGE_WRITE;
+ }
+ } else {
+ ctx->prot |= PAGE_WRITE;
+ }
+
+ return ret;
+}
+
+int get_physical_address (CPUState *env, mmu_ctx_t *ctx, target_ulong eaddr,
+ int rw, int access_type, int check_BATs)
+{
int ret;
#if 0
- if (loglevel > 0) {
+ if (loglevel != 0) {
fprintf(logfile, "%s\n", __func__);
}
-#endif
+#endif
if ((access_type == ACCESS_CODE && msr_ir == 0) ||
(access_type != ACCESS_CODE && msr_dr == 0)) {
/* No address translation */
- *physical = address & ~0xFFF;
- *prot = PAGE_READ | PAGE_WRITE;
- ret = 0;
+ ret = check_physical(env, ctx, eaddr, rw);
} else {
- /* Try to find a BAT */
- ret = get_bat(env, physical, prot, address, rw, access_type);
- if (ret < 0) {
- /* We didn't match any BAT entry */
- ret = get_segment(env, physical, prot, address, rw, access_type);
+ ret = -1;
+ switch (PPC_MMU(env)) {
+ case PPC_FLAGS_MMU_32B:
+ case PPC_FLAGS_MMU_SOFT_6xx:
+ /* Try to find a BAT */
+ if (check_BATs)
+ ret = get_bat(env, ctx, eaddr, rw, access_type);
+ /* No break here */
+#if defined(TARGET_PPC64)
+ case PPC_FLAGS_MMU_64B:
+ case PPC_FLAGS_MMU_64BRIDGE:
+#endif
+ if (ret < 0) {
+ /* We didn't match any BAT entry or don't have BATs */
+ ret = get_segment(env, ctx, eaddr, rw, access_type);
+ }
+ break;
+ case PPC_FLAGS_MMU_SOFT_4xx:
+ case PPC_FLAGS_MMU_403:
+ ret = mmu4xx_get_physical_address(env, ctx, eaddr,
+ rw, access_type);
+ break;
+ case PPC_FLAGS_MMU_601:
+ /* XXX: TODO */
+ cpu_abort(env, "601 MMU model not implemented\n");
+ return -1;
+ case PPC_FLAGS_MMU_BOOKE:
+ /* XXX: TODO */
+ cpu_abort(env, "BookeE MMU model not implemented\n");
+ return -1;
+ case PPC_FLAGS_MMU_BOOKE_FSL:
+ /* XXX: TODO */
+ cpu_abort(env, "BookE FSL MMU model not implemented\n");
+ return -1;
+ default:
+ cpu_abort(env, "Unknown or invalid MMU model\n");
+ return -1;
}
}
#if 0
- if (loglevel > 0) {
- fprintf(logfile, "%s address %08x => %08x\n",
- __func__, address, *physical);
+ if (loglevel != 0) {
+ fprintf(logfile, "%s address " ADDRX " => %d " PADDRX "\n",
+ __func__, eaddr, ret, ctx->raddr);
}
-#endif
+#endif
+
return ret;
}
-target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
+target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr)
{
- uint32_t phys_addr;
- int prot;
+ mmu_ctx_t ctx;
- if (get_physical_address(env, &phys_addr, &prot, addr, 0, ACCESS_INT) != 0)
+ if (unlikely(get_physical_address(env, &ctx, addr, 0, ACCESS_INT, 1) != 0))
return -1;
- return phys_addr;
+
+ return ctx.raddr & TARGET_PAGE_MASK;
}
/* Perform address translation */
-int cpu_ppc_handle_mmu_fault (CPUState *env, uint32_t address, int rw,
+int cpu_ppc_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
int is_user, int is_softmmu)
{
- uint32_t physical;
- int prot;
+ mmu_ctx_t ctx;
int exception = 0, error_code = 0;
int access_type;
int ret = 0;
@@ -444,35 +950,71 @@
access_type = ACCESS_INT;
// access_type = env->access_type;
}
- if (env->user_mode_only) {
- /* user mode only emulation */
- ret = -2;
- goto do_fault;
- }
- ret = get_physical_address(env, &physical, &prot,
- address, rw, access_type);
+ ret = get_physical_address(env, &ctx, address, rw, access_type, 1);
if (ret == 0) {
- ret = tlb_set_page(env, address & ~0xFFF, physical, prot,
- is_user, is_softmmu);
+ ret = tlb_set_page(env, address & TARGET_PAGE_MASK,
+ ctx.raddr & TARGET_PAGE_MASK, ctx.prot,
+ is_user, is_softmmu);
} else if (ret < 0) {
- do_fault:
#if defined (DEBUG_MMU)
- if (loglevel > 0)
- cpu_dump_state(env, logfile, fprintf, 0);
+ if (loglevel != 0)
+ cpu_dump_state(env, logfile, fprintf, 0);
#endif
if (access_type == ACCESS_CODE) {
exception = EXCP_ISI;
switch (ret) {
case -1:
- /* No matches in page tables */
- error_code = 0x40000000;
+ /* No matches in page tables or TLB */
+ switch (PPC_MMU(env)) {
+ case PPC_FLAGS_MMU_SOFT_6xx:
+ exception = EXCP_I_TLBMISS;
+ env->spr[SPR_IMISS] = address;
+ env->spr[SPR_ICMP] = 0x80000000 | ctx.ptem;
+ error_code = 1 << 18;
+ goto tlb_miss;
+ case PPC_FLAGS_MMU_SOFT_4xx:
+ case PPC_FLAGS_MMU_403:
+ exception = EXCP_40x_ITLBMISS;
+ error_code = 0;
+ env->spr[SPR_40x_DEAR] = address;
+ env->spr[SPR_40x_ESR] = 0x00000000;
+ break;
+ case PPC_FLAGS_MMU_32B:
+ error_code = 0x40000000;
+ break;
+#if defined(TARGET_PPC64)
+ case PPC_FLAGS_MMU_64B:
+ /* XXX: TODO */
+ cpu_abort(env, "MMU model not implemented\n");
+ return -1;
+ case PPC_FLAGS_MMU_64BRIDGE:
+ /* XXX: TODO */
+ cpu_abort(env, "MMU model not implemented\n");
+ return -1;
+#endif
+ case PPC_FLAGS_MMU_601:
+ /* XXX: TODO */
+ cpu_abort(env, "MMU model not implemented\n");
+ return -1;
+ case PPC_FLAGS_MMU_BOOKE:
+ /* XXX: TODO */
+ cpu_abort(env, "MMU model not implemented\n");
+ return -1;
+ case PPC_FLAGS_MMU_BOOKE_FSL:
+ /* XXX: TODO */
+ cpu_abort(env, "MMU model not implemented\n");
+ return -1;
+ default:
+ cpu_abort(env, "Unknown or invalid MMU model\n");
+ return -1;
+ }
break;
case -2:
/* Access rights violation */
error_code = 0x08000000;
break;
case -3:
- /* No execute protection violation */
+ /* No execute protection violation */
error_code = 0x10000000;
break;
case -4:
@@ -490,8 +1032,63 @@
exception = EXCP_DSI;
switch (ret) {
case -1:
- /* No matches in page tables */
- error_code = 0x40000000;
+ /* No matches in page tables or TLB */
+ switch (PPC_MMU(env)) {
+ case PPC_FLAGS_MMU_SOFT_6xx:
+ if (rw == 1) {
+ exception = EXCP_DS_TLBMISS;
+ error_code = 1 << 16;
+ } else {
+ exception = EXCP_DL_TLBMISS;
+ error_code = 0;
+ }
+ env->spr[SPR_DMISS] = address;
+ env->spr[SPR_DCMP] = 0x80000000 | ctx.ptem;
+ tlb_miss:
+ error_code |= ctx.key << 19;
+ env->spr[SPR_HASH1] = ctx.pg_addr[0];
+ env->spr[SPR_HASH2] = ctx.pg_addr[1];
+ /* Do not alter DAR nor DSISR */
+ goto out;
+ case PPC_FLAGS_MMU_SOFT_4xx:
+ case PPC_FLAGS_MMU_403:
+ exception = EXCP_40x_DTLBMISS;
+ error_code = 0;
+ env->spr[SPR_40x_DEAR] = address;
+ if (rw)
+ env->spr[SPR_40x_ESR] = 0x00800000;
+ else
+ env->spr[SPR_40x_ESR] = 0x00000000;
+ break;
+ case PPC_FLAGS_MMU_32B:
+ error_code = 0x40000000;
+ break;
+#if defined(TARGET_PPC64)
+ case PPC_FLAGS_MMU_64B:
+ /* XXX: TODO */
+ cpu_abort(env, "MMU model not implemented\n");
+ return -1;
+ case PPC_FLAGS_MMU_64BRIDGE:
+ /* XXX: TODO */
+ cpu_abort(env, "MMU model not implemented\n");
+ return -1;
+#endif
+ case PPC_FLAGS_MMU_601:
+ /* XXX: TODO */
+ cpu_abort(env, "MMU model not implemented\n");
+ return -1;
+ case PPC_FLAGS_MMU_BOOKE:
+ /* XXX: TODO */
+ cpu_abort(env, "MMU model not implemented\n");
+ return -1;
+ case PPC_FLAGS_MMU_BOOKE_FSL:
+ /* XXX: TODO */
+ cpu_abort(env, "MMU model not implemented\n");
+ return -1;
+ default:
+ cpu_abort(env, "Unknown or invalid MMU model\n");
+ return -1;
+ }
break;
case -2:
/* Access rights violation */
@@ -514,7 +1111,7 @@
error_code = 0x04100000;
break;
default:
- printf("DSI: invalid exception (%d)\n", ret);
+ printf("DSI: invalid exception (%d)\n", ret);
exception = EXCP_PROGRAM;
error_code = EXCP_INVAL | EXCP_INVAL_INVAL;
break;
@@ -528,10 +1125,11 @@
}
if (exception == EXCP_DSI && rw == 1)
error_code |= 0x02000000;
- /* Store fault address */
- env->spr[SPR_DAR] = address;
+ /* Store fault address */
+ env->spr[SPR_DAR] = address;
env->spr[SPR_DSISR] = error_code;
}
+ out:
#if 0
printf("%s: set exception to %d %02x\n",
__func__, exception, error_code);
@@ -540,9 +1138,9 @@
env->error_code = error_code;
ret = 1;
}
+
return ret;
}
-#endif
/*****************************************************************************/
/* BATs management */
@@ -551,11 +1149,14 @@
target_ulong BATu, target_ulong mask)
{
target_ulong base, end, page;
+
base = BATu & ~0x0001FFFF;
end = base + mask + 0x00020000;
#if defined (DEBUG_BATS)
- if (loglevel != 0)
- fprintf(logfile, "Flush BAT from %08x to %08x (%08x)\n", base, end, mask);
+ if (loglevel != 0) {
+ fprintf(logfile, "Flush BAT from " ADDRX " to " ADDRX " (" ADDRX ")\n",
+ base, end, mask);
+ }
#endif
for (page = base; page != end; page += TARGET_PAGE_SIZE)
tlb_flush_page(env, page);
@@ -571,9 +1172,8 @@
{
#if defined (DEBUG_BATS)
if (loglevel != 0) {
- fprintf(logfile, "Set %cBAT%d%c to 0x%08lx (0x%08lx)\n",
- ID, nr, ul == 0 ? 'u' : 'l', (unsigned long)value,
- (unsigned long)env->nip);
+ fprintf(logfile, "Set %cBAT%d%c to 0x" ADDRX " (0x" ADDRX ")\n",
+ ID, nr, ul == 0 ? 'u' : 'l', value, env->nip);
}
#endif
}
@@ -608,8 +1208,7 @@
(env->IBAT[1][nr] & ~0x0001FFFF & ~mask);
#if !defined(FLUSH_ALL_TLBS)
do_invalidate_BAT(env, env->IBAT[0][nr], mask);
-#endif
-#if defined(FLUSH_ALL_TLBS)
+#else
tlb_flush(env, 1);
#endif
}
@@ -663,23 +1262,36 @@
env->DBAT[1][nr] = value;
}
-static inline void invalidate_all_tlbs (CPUPPCState *env)
+
+/*****************************************************************************/
+/* TLB management */
+void ppc_tlb_invalidate_all (CPUPPCState *env)
{
- /* XXX: this needs to be completed for sotware driven TLB support */
- tlb_flush(env, 1);
+ if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_6xx)) {
+ ppc6xx_tlb_invalidate_all(env);
+ } else if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_4xx)) {
+ ppc4xx_tlb_invalidate_all(env);
+ } else {
+ tlb_flush(env, 1);
+ }
}
/*****************************************************************************/
/* Special registers manipulation */
-target_ulong do_load_nip (CPUPPCState *env)
+#if defined(TARGET_PPC64)
+target_ulong ppc_load_asr (CPUPPCState *env)
{
- return env->nip;
+ return env->asr;
}
-void do_store_nip (CPUPPCState *env, target_ulong value)
+void ppc_store_asr (CPUPPCState *env, target_ulong value)
{
- env->nip = value;
+ if (env->asr != value) {
+ env->asr = value;
+ tlb_flush(env, 1);
+ }
}
+#endif
target_ulong do_load_sdr1 (CPUPPCState *env)
{
@@ -690,12 +1302,12 @@
{
#if defined (DEBUG_MMU)
if (loglevel != 0) {
- fprintf(logfile, "%s: 0x%08lx\n", __func__, (unsigned long)value);
+ fprintf(logfile, "%s: 0x" ADDRX "\n", __func__, value);
}
#endif
if (env->sdr1 != value) {
env->sdr1 = value;
- invalidate_all_tlbs(env);
+ tlb_flush(env, 1);
}
}
@@ -708,8 +1320,8 @@
{
#if defined (DEBUG_MMU)
if (loglevel != 0) {
- fprintf(logfile, "%s: reg=%d 0x%08lx %08lx\n",
- __func__, srnum, (unsigned long)value, env->sr[srnum]);
+ fprintf(logfile, "%s: reg=%d 0x" ADDRX " " ADDRX "\n",
+ __func__, srnum, value, env->sr[srnum]);
}
#endif
if (env->sr[srnum] != value) {
@@ -724,35 +1336,14 @@
tlb_flush_page(env, page);
}
#else
- invalidate_all_tlbs(env);
+ tlb_flush(env, 1);
#endif
}
}
+#endif /* !defined (CONFIG_USER_ONLY) */
-uint32_t do_load_cr (CPUPPCState *env)
+uint32_t ppc_load_xer (CPUPPCState *env)
{
- return (env->crf[0] << 28) |
- (env->crf[1] << 24) |
- (env->crf[2] << 20) |
- (env->crf[3] << 16) |
- (env->crf[4] << 12) |
- (env->crf[5] << 8) |
- (env->crf[6] << 4) |
- (env->crf[7] << 0);
-}
-
-void do_store_cr (CPUPPCState *env, uint32_t value, uint32_t mask)
-{
- int i, sh;
-
- for (i = 0, sh = 7; i < 8; i++, sh --) {
- if (mask & (1 << sh))
- env->crf[i] = (value >> (sh * 4)) & 0xFUL;
- }
-}
-
-uint32_t do_load_xer (CPUPPCState *env)
-{
return (xer_so << XER_SO) |
(xer_ov << XER_OV) |
(xer_ca << XER_CA) |
@@ -760,49 +1351,67 @@
(xer_cmp << XER_CMP);
}
-void do_store_xer (CPUPPCState *env, uint32_t value)
+void ppc_store_xer (CPUPPCState *env, uint32_t value)
{
xer_so = (value >> XER_SO) & 0x01;
xer_ov = (value >> XER_OV) & 0x01;
xer_ca = (value >> XER_CA) & 0x01;
xer_cmp = (value >> XER_CMP) & 0xFF;
- xer_bc = (value >> XER_BC) & 0x3F;
+ xer_bc = (value >> XER_BC) & 0x7F;
}
-target_ulong do_load_msr (CPUPPCState *env)
+/* Swap temporary saved registers with GPRs */
+static inline void swap_gpr_tgpr (CPUPPCState *env)
{
- return (msr_vr << MSR_VR) |
- (msr_ap << MSR_AP) |
- (msr_sa << MSR_SA) |
- (msr_key << MSR_KEY) |
- (msr_pow << MSR_POW) |
- (msr_tlb << MSR_TLB) |
- (msr_ile << MSR_ILE) |
- (msr_ee << MSR_EE) |
- (msr_pr << MSR_PR) |
- (msr_fp << MSR_FP) |
- (msr_me << MSR_ME) |
- (msr_fe0 << MSR_FE0) |
- (msr_se << MSR_SE) |
- (msr_be << MSR_BE) |
- (msr_fe1 << MSR_FE1) |
- (msr_al << MSR_AL) |
- (msr_ip << MSR_IP) |
- (msr_ir << MSR_IR) |
- (msr_dr << MSR_DR) |
- (msr_pe << MSR_PE) |
- (msr_px << MSR_PX) |
- (msr_ri << MSR_RI) |
- (msr_le << MSR_LE);
+ ppc_gpr_t tmp;
+
+ tmp = env->gpr[0];
+ env->gpr[0] = env->tgpr[0];
+ env->tgpr[0] = tmp;
+ tmp = env->gpr[1];
+ env->gpr[1] = env->tgpr[1];
+ env->tgpr[1] = tmp;
+ tmp = env->gpr[2];
+ env->gpr[2] = env->tgpr[2];
+ env->tgpr[2] = tmp;
+ tmp = env->gpr[3];
+ env->gpr[3] = env->tgpr[3];
+ env->tgpr[3] = tmp;
}
-void do_compute_hflags (CPUPPCState *env)
+/* GDBstub can read and write MSR... */
+target_ulong do_load_msr (CPUPPCState *env)
{
- /* Compute current hflags */
- env->hflags = (msr_pr << MSR_PR) | (msr_le << MSR_LE) |
- (msr_fp << MSR_FP) | (msr_fe0 << MSR_FE0) | (msr_fe1 << MSR_FE1) |
- (msr_vr << MSR_VR) | (msr_ap << MSR_AP) | (msr_sa << MSR_SA) |
- (msr_se << MSR_SE) | (msr_be << MSR_BE);
+ return
+#if defined (TARGET_PPC64)
+ ((target_ulong)msr_sf << MSR_SF) |
+ ((target_ulong)msr_isf << MSR_ISF) |
+ ((target_ulong)msr_hv << MSR_HV) |
+#endif
+ ((target_ulong)msr_ucle << MSR_UCLE) |
+ ((target_ulong)msr_vr << MSR_VR) | /* VR / SPE */
+ ((target_ulong)msr_ap << MSR_AP) |
+ ((target_ulong)msr_sa << MSR_SA) |
+ ((target_ulong)msr_key << MSR_KEY) |
+ ((target_ulong)msr_pow << MSR_POW) | /* POW / WE */
+ ((target_ulong)msr_tlb << MSR_TLB) | /* TLB / TGPE / CE */
+ ((target_ulong)msr_ile << MSR_ILE) |
+ ((target_ulong)msr_ee << MSR_EE) |
+ ((target_ulong)msr_pr << MSR_PR) |
+ ((target_ulong)msr_fp << MSR_FP) |
+ ((target_ulong)msr_me << MSR_ME) |
+ ((target_ulong)msr_fe0 << MSR_FE0) |
+ ((target_ulong)msr_se << MSR_SE) | /* SE / DWE / UBLE */
+ ((target_ulong)msr_be << MSR_BE) | /* BE / DE */
+ ((target_ulong)msr_fe1 << MSR_FE1) |
+ ((target_ulong)msr_al << MSR_AL) |
+ ((target_ulong)msr_ip << MSR_IP) |
+ ((target_ulong)msr_ir << MSR_IR) | /* IR / IS */
+ ((target_ulong)msr_dr << MSR_DR) | /* DR / DS */
+ ((target_ulong)msr_pe << MSR_PE) | /* PE / EP */
+ ((target_ulong)msr_px << MSR_PX) | /* PX / PMM */
+ ((target_ulong)msr_ri << MSR_RI) |
+ ((target_ulong)msr_le << MSR_LE);
}
void do_store_msr (CPUPPCState *env, target_ulong value)
@@ -812,10 +1421,7 @@
value &= env->msr_mask;
if (((value >> MSR_IR) & 1) != msr_ir ||
((value >> MSR_DR) & 1) != msr_dr) {
- /* Flush all tlb when changing translation mode
- * When using software driven TLB, we may also need to reload
- * all defined TLBs
- */
+ /* Flush all tlb when changing translation mode */
tlb_flush(env, 1);
env->interrupt_request |= CPU_INTERRUPT_EXITTB;
}
@@ -824,35 +1430,63 @@
fprintf(logfile, "%s: T0 %08lx\n", __func__, value);
}
#endif
- msr_vr = (value >> MSR_VR) & 1;
- msr_ap = (value >> MSR_AP) & 1;
- msr_sa = (value >> MSR_SA) & 1;
- msr_key = (value >> MSR_KEY) & 1;
- msr_pow = (value >> MSR_POW) & 1;
- msr_tlb = (value >> MSR_TLB) & 1;
- msr_ile = (value >> MSR_ILE) & 1;
- msr_ee = (value >> MSR_EE) & 1;
- msr_pr = (value >> MSR_PR) & 1;
- msr_fp = (value >> MSR_FP) & 1;
- msr_me = (value >> MSR_ME) & 1;
- msr_fe0 = (value >> MSR_FE0) & 1;
- msr_se = (value >> MSR_SE) & 1;
- msr_be = (value >> MSR_BE) & 1;
- msr_fe1 = (value >> MSR_FE1) & 1;
- msr_al = (value >> MSR_AL) & 1;
- msr_ip = (value >> MSR_IP) & 1;
- msr_ir = (value >> MSR_IR) & 1;
- msr_dr = (value >> MSR_DR) & 1;
- msr_pe = (value >> MSR_PE) & 1;
- msr_px = (value >> MSR_PX) & 1;
- msr_ri = (value >> MSR_RI) & 1;
- msr_le = (value >> MSR_LE) & 1;
+ switch (PPC_EXCP(env)) {
+ case PPC_FLAGS_EXCP_602:
+ case PPC_FLAGS_EXCP_603:
+ if (((value >> MSR_TGPR) & 1) != msr_tgpr) {
+ /* Swap temporary saved registers with GPRs */
+ swap_gpr_tgpr(env);
+ }
+ break;
+ default:
+ break;
+ }
+#if defined (TARGET_PPC64)
+ msr_sf = (value >> MSR_SF) & 1;
+ msr_isf = (value >> MSR_ISF) & 1;
+ msr_hv = (value >> MSR_HV) & 1;
+#endif
+ msr_ucle = (value >> MSR_UCLE) & 1;
+ msr_vr = (value >> MSR_VR) & 1; /* VR / SPE */
+ msr_ap = (value >> MSR_AP) & 1;
+ msr_sa = (value >> MSR_SA) & 1;
+ msr_key = (value >> MSR_KEY) & 1;
+ msr_pow = (value >> MSR_POW) & 1; /* POW / WE */
+ msr_tlb = (value >> MSR_TLB) & 1; /* TLB / TGPR / CE */
+ msr_ile = (value >> MSR_ILE) & 1;
+ msr_ee = (value >> MSR_EE) & 1;
+ msr_pr = (value >> MSR_PR) & 1;
+ msr_fp = (value >> MSR_FP) & 1;
+ msr_me = (value >> MSR_ME) & 1;
+ msr_fe0 = (value >> MSR_FE0) & 1;
+ msr_se = (value >> MSR_SE) & 1; /* SE / DWE / UBLE */
+ msr_be = (value >> MSR_BE) & 1; /* BE / DE */
+ msr_fe1 = (value >> MSR_FE1) & 1;
+ msr_al = (value >> MSR_AL) & 1;
+ msr_ip = (value >> MSR_IP) & 1;
+ msr_ir = (value >> MSR_IR) & 1; /* IR / IS */
+ msr_dr = (value >> MSR_DR) & 1; /* DR / DS */
+ msr_pe = (value >> MSR_PE) & 1; /* PE / EP */
+ msr_px = (value >> MSR_PX) & 1; /* PX / PMM */
+ msr_ri = (value >> MSR_RI) & 1;
+ msr_le = (value >> MSR_LE) & 1;
do_compute_hflags(env);
enter_pm = 0;
switch (PPC_EXCP(env)) {
+ case PPC_FLAGS_EXCP_603:
+ /* Don't handle SLEEP mode: we should disable all clocks...
+ * No dynamic power-management.
+ */
+ if (msr_pow == 1 && (env->spr[SPR_HID0] & 0x00C00000) != 0)
+ enter_pm = 1;
+ break;
+ case PPC_FLAGS_EXCP_604:
+ if (msr_pow == 1)
+ enter_pm = 1;
+ break;
case PPC_FLAGS_EXCP_7x0:
- if (msr_pow == 1 && (env->spr[SPR_HID0] & 0x00E00000) != 0)
+ if (msr_pow == 1 && (env->spr[SPR_HID0] & 0x00E00000) != 0)
enter_pm = 1;
break;
default:
@@ -866,75 +1500,25 @@
}
}
-float64 do_load_fpscr (CPUPPCState *env)
+#if defined(TARGET_PPC64)
+void ppc_store_msr_32 (CPUPPCState *env, uint32_t value)
{
- /* The 32 MSB of the target fpr are undefined.
- * They'll be zero...
- */
- union {
- float64 d;
- struct {
- uint32_t u[2];
- } s;
- } u;
- int i;
-
-#ifdef WORDS_BIGENDIAN
-#define WORD0 0
-#define WORD1 1
-#else
-#define WORD0 1
-#define WORD1 0
+ do_store_msr(env,
+ (do_load_msr(env) & ~0xFFFFFFFFULL) | (value & 0xFFFFFFFF));
+}
#endif
- u.s.u[WORD0] = 0;
- u.s.u[WORD1] = 0;
- for (i = 0; i < 8; i++)
- u.s.u[WORD1] |= env->fpscr[i] << (4 * i);
- return u.d;
-}
-void do_store_fpscr (CPUPPCState *env, float64 f, uint32_t mask)
+void do_compute_hflags (CPUPPCState *env)
{
- /*
- * We use only the 32 LSB of the incoming fpr
- */
- union {
- double d;
- struct {
- uint32_t u[2];
- } s;
- } u;
- int i, rnd_type;
-
- u.d = f;
- if (mask & 0x80)
- env->fpscr[0] = (env->fpscr[0] & 0x9) | ((u.s.u[WORD1] >> 28) & ~0x9);
- for (i = 1; i < 7; i++) {
- if (mask & (1 << (7 - i)))
- env->fpscr[i] = (u.s.u[WORD1] >> (4 * (7 - i))) & 0xF;
- }
- /* TODO: update FEX & VX */
- /* Set rounding mode */
- switch (env->fpscr[0] & 0x3) {
- case 0:
- /* Best approximation (round to nearest) */
- rnd_type = float_round_nearest_even;
- break;
- case 1:
- /* Smaller magnitude (round toward zero) */
- rnd_type = float_round_to_zero;
- break;
- case 2:
- /* Round toward +infinite */
- rnd_type = float_round_up;
- break;
- default:
- case 3:
- /* Round toward -infinite */
- rnd_type = float_round_down;
- break;
- }
- set_float_rounding_mode(rnd_type, &env->fp_status);
+ /* Compute current hflags */
+ env->hflags = (msr_cm << MSR_CM) | (msr_vr << MSR_VR) |
+ (msr_ap << MSR_AP) | (msr_sa << MSR_SA) | (msr_pr << MSR_PR) |
+ (msr_fp << MSR_FP) | (msr_fe0 << MSR_FE0) | (msr_se << MSR_SE) |
+ (msr_be << MSR_BE) | (msr_fe1 << MSR_FE1) | (msr_le << MSR_LE);
+#if defined (TARGET_PPC64)
+ /* No care here: PowerPC 64 MSR_SF means the same as MSR_CM for BookE */
+ env->hflags |= (msr_sf << (MSR_SF - 32)) | (msr_hv << (MSR_HV - 32));
+#endif
}
/*****************************************************************************/
@@ -944,58 +1528,85 @@
{
env->exception_index = -1;
}
-#else
+
+void ppc_hw_interrupt (CPUState *env)
+{
+ env->exception_index = -1;
+}
+#else /* defined (CONFIG_USER_ONLY) */
static void dump_syscall(CPUState *env)
{
- fprintf(logfile, "syscall r0=0x%08x r3=0x%08x r4=0x%08x r5=0x%08x r6=0x%08x nip=0x%08x\n",
+ fprintf(logfile, "syscall r0=0x" REGX " r3=0x" REGX " r4=0x" REGX
+ " r5=0x" REGX " r6=0x" REGX " nip=0x" ADDRX "\n",
env->gpr[0], env->gpr[3], env->gpr[4],
env->gpr[5], env->gpr[6], env->nip);
}
void do_interrupt (CPUState *env)
{
- target_ulong msr, *srr_0, *srr_1, tmp;
- int excp;
+ target_ulong msr, *srr_0, *srr_1, *asrr_0, *asrr_1;
+ int excp, idx;
excp = env->exception_index;
msr = do_load_msr(env);
/* The default is to use SRR0 & SRR1 to save the exception context */
srr_0 = &env->spr[SPR_SRR0];
srr_1 = &env->spr[SPR_SRR1];
+ asrr_0 = NULL;
+ asrr_1 = NULL;
#if defined (DEBUG_EXCEPTIONS)
if ((excp == EXCP_PROGRAM || excp == EXCP_DSI) && msr_pr == 1) {
if (loglevel != 0) {
- fprintf(logfile, "Raise exception at 0x%08lx => 0x%08x (%02x)\n",
- (unsigned long)env->nip, excp, env->error_code);
- cpu_dump_state(env, logfile, fprintf, 0);
+ fprintf(logfile,
+ "Raise exception at 0x" ADDRX " => 0x%08x (%02x)\n",
+ env->nip, excp, env->error_code);
+ cpu_dump_state(env, logfile, fprintf, 0);
}
}
#endif
if (loglevel & CPU_LOG_INT) {
- fprintf(logfile, "Raise exception at 0x%08lx => 0x%08x (%02x)\n",
- (unsigned long)env->nip, excp, env->error_code);
+ fprintf(logfile, "Raise exception at 0x" ADDRX " => 0x%08x (%02x)\n",
+ env->nip, excp, env->error_code);
}
msr_pow = 0;
+ idx = -1;
/* Generate informations in save/restore registers */
switch (excp) {
- /* Generic PowerPC exceptions */
+ /* Generic PowerPC exceptions */
case EXCP_RESET: /* 0x0100 */
- if (PPC_EXCP(env) != PPC_FLAGS_EXCP_40x) {
+ switch (PPC_EXCP(env)) {
+ case PPC_FLAGS_EXCP_40x:
+ srr_0 = &env->spr[SPR_40x_SRR2];
+ srr_1 = &env->spr[SPR_40x_SRR3];
+ break;
+ case PPC_FLAGS_EXCP_BOOKE:
+ idx = 0;
+ srr_0 = &env->spr[SPR_BOOKE_CSRR0];
+ srr_1 = &env->spr[SPR_BOOKE_CSRR1];
+ break;
+ default:
if (msr_ip)
excp += 0xFFC00;
excp |= 0xFFC00000;
- } else {
- srr_0 = &env->spr[SPR_40x_SRR2];
- srr_1 = &env->spr[SPR_40x_SRR3];
+ break;
}
goto store_next;
case EXCP_MACHINE_CHECK: /* 0x0200 */
- if (msr_me == 0) {
- cpu_abort(env, "Machine check exception while not allowed\n");
- }
- if (PPC_EXCP(env) == PPC_FLAGS_EXCP_40x) {
+ switch (PPC_EXCP(env)) {
+ case PPC_FLAGS_EXCP_40x:
srr_0 = &env->spr[SPR_40x_SRR2];
srr_1 = &env->spr[SPR_40x_SRR3];
+ break;
+ case PPC_FLAGS_EXCP_BOOKE:
+ idx = 1;
+ srr_0 = &env->spr[SPR_BOOKE_MCSRR0];
+ srr_1 = &env->spr[SPR_BOOKE_MCSRR1];
+ asrr_0 = &env->spr[SPR_BOOKE_CSRR0];
+ asrr_1 = &env->spr[SPR_BOOKE_CSRR1];
+ msr_ce = 0;
+ break;
+ default:
+ break;
}
msr_me = 0;
break;
@@ -1004,43 +1615,34 @@
/* data location address has been stored
* when the fault has been detected
*/
- msr &= ~0xFFFF0000;
+ idx = 2;
+ msr &= ~0xFFFF0000;
#if defined (DEBUG_EXCEPTIONS)
- if (loglevel) {
- fprintf(logfile, "DSI exception: DSISR=0x%08x, DAR=0x%08x\n",
- env->spr[SPR_DSISR], env->spr[SPR_DAR]);
- } else {
- printf("DSI exception: DSISR=0x%08x, DAR=0x%08x\n",
- env->spr[SPR_DSISR], env->spr[SPR_DAR]);
- }
+ if (loglevel != 0) {
+ fprintf(logfile, "DSI exception: DSISR=0x" ADDRX" DAR=0x" ADDRX
+ "\n", env->spr[SPR_DSISR], env->spr[SPR_DAR]);
+ }
#endif
goto store_next;
case EXCP_ISI: /* 0x0400 */
/* Store exception cause */
- msr &= ~0xFFFF0000;
+ idx = 3;
+ msr &= ~0xFFFF0000;
msr |= env->error_code;
#if defined (DEBUG_EXCEPTIONS)
- if (loglevel != 0) {
- fprintf(logfile, "ISI exception: msr=0x%08x, nip=0x%08x\n",
- msr, env->nip);
- }
+ if (loglevel != 0) {
+ fprintf(logfile, "ISI exception: msr=0x" ADDRX ", nip=0x" ADDRX
+ "\n", msr, env->nip);
+ }
#endif
goto store_next;
case EXCP_EXTERNAL: /* 0x0500 */
- if (msr_ee == 0) {
-#if defined (DEBUG_EXCEPTIONS)
- if (loglevel > 0) {
- fprintf(logfile, "Skipping hardware interrupt\n");
- }
-#endif
- /* Requeue it */
- env->interrupt_request |= CPU_INTERRUPT_HARD;
- return;
- }
+ idx = 4;
goto store_next;
case EXCP_ALIGN: /* 0x0600 */
- if (PPC_EXCP(env) != PPC_FLAGS_EXCP_601) {
+ if (likely(PPC_EXCP(env) != PPC_FLAGS_EXCP_601)) {
/* Store exception cause */
+ idx = 5;
/* Get rS/rD and rA from faulting opcode */
env->spr[SPR_DSISR] |=
(ldl_code((env->nip - 4)) & 0x03FF0000) >> 16;
@@ -1055,15 +1657,18 @@
}
goto store_current;
case EXCP_PROGRAM: /* 0x0700 */
+ idx = 6;
msr &= ~0xFFFF0000;
switch (env->error_code & ~0xF) {
case EXCP_FP:
if (msr_fe0 == 0 && msr_fe1 == 0) {
#if defined (DEBUG_EXCEPTIONS)
- printf("Ignore floating point exception\n");
+ if (loglevel != 0) {
+ fprintf(logfile, "Ignore floating point exception\n");
+ }
#endif
return;
- }
+ }
msr |= 0x00100000;
/* Set FX */
env->fpscr[7] |= 0x8;
@@ -1071,36 +1676,37 @@
if ((((env->fpscr[7] & 0x3) << 3) | (env->fpscr[6] >> 1)) &
((env->fpscr[1] << 1) | (env->fpscr[0] >> 3)))
env->fpscr[7] |= 0x4;
- break;
+ break;
case EXCP_INVAL:
- // printf("Invalid instruction at 0x%08x\n", env->nip);
+#if defined (DEBUG_EXCEPTIONS)
+ if (loglevel != 0) {
+ fprintf(logfile, "Invalid instruction at 0x" ADDRX "\n",
+ env->nip);
+ }
+#endif
msr |= 0x00080000;
- break;
+ break;
case EXCP_PRIV:
msr |= 0x00040000;
- break;
+ break;
case EXCP_TRAP:
+ idx = 15;
msr |= 0x00020000;
break;
default:
/* Should never occur */
- break;
- }
+ break;
+ }
msr |= 0x00010000;
goto store_current;
case EXCP_NO_FP: /* 0x0800 */
+ idx = 7;
msr &= ~0xFFFF0000;
goto store_current;
case EXCP_DECR:
- if (msr_ee == 0) {
-#if 1
- /* Requeue it */
- env->interrupt_request |= CPU_INTERRUPT_TIMER;
-#endif
- return;
- }
goto store_next;
case EXCP_SYSCALL: /* 0x0C00 */
+ idx = 8;
/* NOTE: this is a temporary hack to support graphics OSI
calls from the MOL driver */
if (env->gpr[3] == 0x113724fa && env->gpr[4] == 0x77810f9b &&
@@ -1125,7 +1731,7 @@
cpu_abort(env, "Floating point assist exception "
"is not implemented yet !\n");
goto store_next;
- /* 64 bits PowerPC exceptions */
+ /* 64 bits PowerPC exceptions */
case EXCP_DSEG: /* 0x0380 */
/* XXX: TODO */
cpu_abort(env, "Data segment exception is not implemented yet !\n");
@@ -1136,19 +1742,14 @@
"Instruction segment exception is not implemented yet !\n");
goto store_next;
case EXCP_HDECR: /* 0x0980 */
- if (msr_ee == 0) {
-#if 1
- /* Requeue it */
- env->interrupt_request |= CPU_INTERRUPT_TIMER;
-#endif
- return;
- }
- cpu_abort(env,
- "Hypervisor decrementer exception is not implemented yet !\n");
+ /* XXX: TODO */
+ cpu_abort(env, "Hypervisor decrementer exception is not implemented "
+ "yet !\n");
goto store_next;
/* Implementation specific exceptions */
case 0x0A00:
- if (PPC_EXCP(env) != PPC_FLAGS_EXCP_602) {
+ if (likely(env->spr[SPR_PVR] == CPU_PPC_G2 ||
+ env->spr[SPR_PVR] == CPU_PPC_G2LE)) {
/* Critical interrupt on G2 */
/* XXX: TODO */
cpu_abort(env, "G2 critical interrupt is not implemented yet !\n");
@@ -1158,6 +1759,7 @@
}
return;
case 0x0F20:
+ idx = 9;
switch (PPC_EXCP(env)) {
case PPC_FLAGS_EXCP_40x:
/* APU unavailable on 405 */
@@ -1177,29 +1779,38 @@
}
return;
case 0x1000:
+ idx = 10;
switch (PPC_EXCP(env)) {
case PPC_FLAGS_EXCP_40x:
/* PIT on 4xx */
- /* XXX: TODO */
- cpu_abort(env, "40x PIT exception is not implemented yet !\n");
+ msr &= ~0xFFFF0000;
+#if defined (DEBUG_EXCEPTIONS)
+ if (loglevel != 0)
+ fprintf(logfile, "PIT exception\n");
+#endif
goto store_next;
case PPC_FLAGS_EXCP_602:
case PPC_FLAGS_EXCP_603:
/* ITLBMISS on 602/603 */
- msr &= ~0xF00F0000;
- msr_tgpr = 1;
goto store_gprs;
+ case PPC_FLAGS_EXCP_7x5:
+ /* ITLBMISS on 745/755 */
+ goto tlb_miss;
default:
cpu_abort(env, "Invalid exception 0x1000 !\n");
break;
}
return;
case 0x1010:
+ idx = 11;
switch (PPC_EXCP(env)) {
case PPC_FLAGS_EXCP_40x:
/* FIT on 4xx */
- cpu_abort(env, "40x FIT exception is not implemented yet !\n");
- /* XXX: TODO */
+ msr &= ~0xFFFF0000;
+#if defined (DEBUG_EXCEPTIONS)
+ if (loglevel != 0)
+ fprintf(logfile, "FIT exception\n");
+#endif
goto store_next;
default:
cpu_abort(env, "Invalid exception 0x1010 !\n");
@@ -1207,79 +1818,93 @@
}
return;
case 0x1020:
+ idx = 12;
switch (PPC_EXCP(env)) {
case PPC_FLAGS_EXCP_40x:
/* Watchdog on 4xx */
- /* XXX: TODO */
- cpu_abort(env,
- "40x watchdog exception is not implemented yet !\n");
+ msr &= ~0xFFFF0000;
+#if defined (DEBUG_EXCEPTIONS)
+ if (loglevel != 0)
+ fprintf(logfile, "WDT exception\n");
+#endif
goto store_next;
+ case PPC_FLAGS_EXCP_BOOKE:
+ srr_0 = &env->spr[SPR_BOOKE_CSRR0];
+ srr_1 = &env->spr[SPR_BOOKE_CSRR1];
+ break;
default:
cpu_abort(env, "Invalid exception 0x1020 !\n");
break;
}
return;
case 0x1100:
+ idx = 13;
switch (PPC_EXCP(env)) {
case PPC_FLAGS_EXCP_40x:
/* DTLBMISS on 4xx */
- /* XXX: TODO */
- cpu_abort(env,
- "40x DTLBMISS exception is not implemented yet !\n");
+ msr &= ~0xFFFF0000;
goto store_next;
case PPC_FLAGS_EXCP_602:
case PPC_FLAGS_EXCP_603:
/* DLTLBMISS on 602/603 */
- msr &= ~0xF00F0000;
- msr_tgpr = 1;
goto store_gprs;
+ case PPC_FLAGS_EXCP_7x5:
+ /* DLTLBMISS on 745/755 */
+ goto tlb_miss;
default:
cpu_abort(env, "Invalid exception 0x1100 !\n");
break;
}
return;
case 0x1200:
+ idx = 14;
switch (PPC_EXCP(env)) {
case PPC_FLAGS_EXCP_40x:
/* ITLBMISS on 4xx */
- /* XXX: TODO */
- cpu_abort(env,
- "40x ITLBMISS exception is not implemented yet !\n");
+ msr &= ~0xFFFF0000;
goto store_next;
case PPC_FLAGS_EXCP_602:
case PPC_FLAGS_EXCP_603:
/* DSTLBMISS on 602/603 */
- msr &= ~0xF00F0000;
+ store_gprs:
+ /* Swap temporary saved registers with GPRs */
+ swap_gpr_tgpr(env);
msr_tgpr = 1;
- store_gprs:
#if defined (DEBUG_SOFTWARE_TLB)
if (loglevel != 0) {
- fprintf(logfile, "6xx %sTLB miss: IM %08x DM %08x IC %08x "
- "DC %08x H1 %08x H2 %08x %08x\n",
- excp == 0x1000 ? "I" : excp == 0x1100 ? "DL" : "DS",
- env->spr[SPR_IMISS], env->spr[SPR_DMISS],
- env->spr[SPR_ICMP], env->spr[SPR_DCMP],
- env->spr[SPR_DHASH1], env->spr[SPR_DHASH2],
+ const unsigned char *es;
+ target_ulong *miss, *cmp;
+ int en;
+ if (excp == 0x1000) {
+ es = "I";
+ en = 'I';
+ miss = &env->spr[SPR_IMISS];
+ cmp = &env->spr[SPR_ICMP];
+ } else {
+ if (excp == 0x1100)
+ es = "DL";
+ else
+ es = "DS";
+ en = 'D';
+ miss = &env->spr[SPR_DMISS];
+ cmp = &env->spr[SPR_DCMP];
+ }
+ fprintf(logfile, "6xx %sTLB miss: %cM " ADDRX " %cC " ADDRX
+ " H1 " ADDRX " H2 " ADDRX " %08x\n",
+ es, en, *miss, en, *cmp,
+ env->spr[SPR_HASH1], env->spr[SPR_HASH2],
env->error_code);
}
#endif
- /* Swap temporary saved registers with GPRs */
- tmp = env->gpr[0];
- env->gpr[0] = env->tgpr[0];
- env->tgpr[0] = tmp;
- tmp = env->gpr[1];
- env->gpr[1] = env->tgpr[1];
- env->tgpr[1] = tmp;
- tmp = env->gpr[2];
- env->gpr[2] = env->tgpr[2];
- env->tgpr[2] = tmp;
- tmp = env->gpr[3];
- env->gpr[3] = env->tgpr[3];
- env->tgpr[3] = tmp;
+ goto tlb_miss;
+ case PPC_FLAGS_EXCP_7x5:
+ /* DSTLBMISS on 745/755 */
+ tlb_miss:
+ msr &= ~0xF83F0000;
msr |= env->crf[0] << 28;
msr |= env->error_code; /* key, D/I, S/L bits */
/* Set way using a LRU mechanism */
- msr |= (env->last_way ^ 1) << 17;
+ msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17;
goto store_next;
default:
cpu_abort(env, "Invalid exception 0x1200 !\n");
@@ -1324,6 +1949,7 @@
switch (PPC_EXCP(env)) {
case PPC_FLAGS_EXCP_602:
/* Watchdog on 602 */
+ /* XXX: TODO */
cpu_abort(env,
"602 watchdog exception is not implemented yet !\n");
goto store_next;
@@ -1408,6 +2034,10 @@
cpu_abort(env,
"601 run mode exception is not implemented yet !\n");
goto store_next;
+ case PPC_FLAGS_EXCP_BOOKE:
+ srr_0 = &env->spr[SPR_BOOKE_CSRR0];
+ srr_1 = &env->spr[SPR_BOOKE_CSRR1];
+ break;
default:
cpu_abort(env, "Invalid exception 0x1800 !\n");
break;
@@ -1422,15 +2052,19 @@
return;
store_current:
/* save current instruction location */
- *srr_0 = (env->nip - 4) & 0xFFFFFFFFULL;
+ *srr_0 = env->nip - 4;
break;
store_next:
/* save next instruction location */
- *srr_0 = env->nip & 0xFFFFFFFFULL;
+ *srr_0 = env->nip;
break;
}
/* Save msr */
*srr_1 = msr;
+ if (asrr_0 != NULL)
+ *asrr_0 = *srr_0;
+ if (asrr_1 != NULL)
+ *asrr_1 = *srr_1;
/* If we disactivated any translation, flush TLBs */
if (msr_ir || msr_dr) {
tlb_flush(env, 1);
@@ -1447,10 +2081,191 @@
msr_dr = 0;
msr_ri = 0;
msr_le = msr_ile;
- msr_sf = msr_isf;
+ if (PPC_EXCP(env) == PPC_FLAGS_EXCP_BOOKE) {
+ msr_cm = msr_icm;
+ if (idx == -1 || (idx >= 16 && idx < 32)) {
+ cpu_abort(env, "Invalid exception index for excp %d %08x idx %d\n",
+ excp, excp, idx);
+ }
+#if defined(TARGET_PPC64)
+ if (msr_cm)
+ env->nip = (uint64_t)env->spr[SPR_BOOKE_IVPR];
+ else
+#endif
+ env->nip = (uint32_t)env->spr[SPR_BOOKE_IVPR];
+ if (idx < 16)
+ env->nip |= env->spr[SPR_BOOKE_IVOR0 + idx];
+ else if (idx < 38)
+ env->nip |= env->spr[SPR_BOOKE_IVOR32 + idx - 32];
+ } else {
+ msr_sf = msr_isf;
+ env->nip = excp;
+ }
do_compute_hflags(env);
/* Jump to handler */
- env->nip = excp;
env->exception_index = EXCP_NONE;
}
+
+void ppc_hw_interrupt (CPUPPCState *env)
+{
+ int raised = 0;
+
+#if 1
+ if (loglevel & CPU_LOG_INT) {
+ fprintf(logfile, "%s: %p pending %08x req %08x me %d ee %d\n",
+ __func__, env, env->pending_interrupts,
+ env->interrupt_request, msr_me, msr_ee);
+ }
+#endif
+ /* Raise it */
+ if (env->pending_interrupts & (1 << PPC_INTERRUPT_RESET)) {
+ /* External reset / critical input */
+ /* XXX: critical input should be handled another way.
+ * This code is not correct !
+ */
+ env->exception_index = EXCP_RESET;
+ env->pending_interrupts &= ~(1 << PPC_INTERRUPT_RESET);
+ raised = 1;
+ }
+ if (raised == 0 && msr_me != 0) {
+ /* Machine check exception */
+ if (env->pending_interrupts & (1 << PPC_INTERRUPT_MCK)) {
+ env->exception_index = EXCP_MACHINE_CHECK;
+ env->pending_interrupts &= ~(1 << PPC_INTERRUPT_MCK);
+ raised = 1;
+ }
+ }
+ if (raised == 0 && msr_ee != 0) {
+#if defined(TARGET_PPC64H) /* PowerPC 64 with hypervisor mode support */
+ /* Hypervisor decrementer exception */
+ if (env->pending_interrupts & (1 << PPC_INTERRUPT_HDECR)) {
+ env->exception_index = EXCP_HDECR;
+ env->pending_interrupts &= ~(1 << PPC_INTERRUPT_HDECR);
+ raised = 1;
+ } else
+#endif
+ /* Decrementer exception */
+ if (env->pending_interrupts & (1 << PPC_INTERRUPT_DECR)) {
+ env->exception_index = EXCP_DECR;
+ env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DECR);
+ raised = 1;
+ /* Programmable interval timer on embedded PowerPC */
+ } else if (env->pending_interrupts & (1 << PPC_INTERRUPT_PIT)) {
+ env->exception_index = EXCP_40x_PIT;
+ env->pending_interrupts &= ~(1 << PPC_INTERRUPT_PIT);
+ raised = 1;
+ /* Fixed interval timer on embedded PowerPC */
+ } else if (env->pending_interrupts & (1 << PPC_INTERRUPT_FIT)) {
+ env->exception_index = EXCP_40x_FIT;
+ env->pending_interrupts &= ~(1 << PPC_INTERRUPT_FIT);
+ raised = 1;
+ /* Watchdog timer on embedded PowerPC */
+ } else if (env->pending_interrupts & (1 << PPC_INTERRUPT_WDT)) {
+ env->exception_index = EXCP_40x_WATCHDOG;
+ env->pending_interrupts &= ~(1 << PPC_INTERRUPT_WDT);
+ raised = 1;
+ /* External interrupt */
+ } else if (env->pending_interrupts & (1 << PPC_INTERRUPT_EXT)) {
+ env->exception_index = EXCP_EXTERNAL;
+ /* Taking an external interrupt does not clear the external
+ * interrupt status
+ */
+#if 0
+ env->pending_interrupts &= ~(1 << PPC_INTERRUPT_EXT);
+#endif
+ raised = 1;
+#if 0 // TODO
+ /* Thermal interrupt */
+ } else if (env->pending_interrupts & (1 << PPC_INTERRUPT_THERM)) {
+ env->exception_index = EXCP_970_THRM;
+ env->pending_interrupts &= ~(1 << PPC_INTERRUPT_THERM);
+ raised = 1;
+#endif
+ }
+#if 0 // TODO
+ /* External debug exception */
+ } else if (env->pending_interrupts & (1 << PPC_INTERRUPT_DEBUG)) {
+ env->exception_index = EXCP_xxx;
+ env->pending_interrupts &= ~(1 << PPC_INTERRUPT_DEBUG);
+ raised = 1;
+#endif
+ }
+ if (raised != 0) {
+ env->error_code = 0;
+ do_interrupt(env);
+ }
+}
#endif /* !CONFIG_USER_ONLY */
+
+void cpu_dump_EA (target_ulong EA)
+{
+ FILE *f;
+
+ if (logfile) {
+ f = logfile;
+ } else {
+ f = stdout;
+ return;
+ }
+ fprintf(f, "Memory access at address " ADDRX "\n", EA);
+}
+
+void cpu_dump_rfi (target_ulong RA, target_ulong msr)
+{
+ FILE *f;
+
+ if (logfile) {
+ f = logfile;
+ } else {
+ f = stdout;
+ return;
+ }
+ fprintf(f, "Return from exception at " ADDRX " with flags " ADDRX "\n",
+ RA, msr);
+}
+
+void cpu_ppc_reset (void *opaque)
+{
+ CPUPPCState *env;
+
+ env = opaque;
+#if defined (DO_SINGLE_STEP) && 0
+ /* Single step trace mode */
+ msr_se = 1;
+ msr_be = 1;
+#endif
+ msr_fp = 1; /* Allow floating point exceptions */
+ msr_me = 1; /* Allow machine check exceptions */
+#if defined(TARGET_PPC64)
+ msr_sf = 0; /* Boot in 32 bits mode */
+ msr_cm = 0;
+#endif
+#if defined(CONFIG_USER_ONLY)
+ msr_pr = 1;
+ tlb_flush(env, 1);
+#else
+ env->nip = 0xFFFFFFFC;
+ ppc_tlb_invalidate_all(env);
+#endif
+ do_compute_hflags(env);
+ env->reserve = -1;
+}
+
+CPUPPCState *cpu_ppc_init (void)
+{
+ CPUPPCState *env;
+
+ env = qemu_mallocz(sizeof(CPUPPCState));
+ if (!env)
+ return NULL;
+ cpu_exec_init(env);
+ cpu_ppc_reset(env);
+
+ return env;
+}
+
+void cpu_ppc_close (CPUPPCState *env)
+{
+ /* Should also remove all opcode tables... */
+ free(env);
+}
Added: trunk/src/host/qemu-neo1973/target-ppc/mfrom_table.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-ppc/mfrom_table.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/target-ppc/mfrom_table.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,79 @@
+static const uint8_t mfrom_ROM_table[602] =
+{
+ 77, 77, 76, 76, 75, 75, 74, 74,
+ 73, 73, 72, 72, 71, 71, 70, 70,
+ 69, 69, 68, 68, 68, 67, 67, 66,
+ 66, 65, 65, 64, 64, 64, 63, 63,
+ 62, 62, 61, 61, 61, 60, 60, 59,
+ 59, 58, 58, 58, 57, 57, 56, 56,
+ 56, 55, 55, 54, 54, 54, 53, 53,
+ 53, 52, 52, 51, 51, 51, 50, 50,
+ 50, 49, 49, 49, 48, 48, 47, 47,
+ 47, 46, 46, 46, 45, 45, 45, 44,
+ 44, 44, 43, 43, 43, 42, 42, 42,
+ 42, 41, 41, 41, 40, 40, 40, 39,
+ 39, 39, 39, 38, 38, 38, 37, 37,
+ 37, 37, 36, 36, 36, 35, 35, 35,
+ 35, 34, 34, 34, 34, 33, 33, 33,
+ 33, 32, 32, 32, 32, 31, 31, 31,
+ 31, 30, 30, 30, 30, 29, 29, 29,
+ 29, 28, 28, 28, 28, 28, 27, 27,
+ 27, 27, 26, 26, 26, 26, 26, 25,
+ 25, 25, 25, 25, 24, 24, 24, 24,
+ 24, 23, 23, 23, 23, 23, 23, 22,
+ 22, 22, 22, 22, 21, 21, 21, 21,
+ 21, 21, 20, 20, 20, 20, 20, 20,
+ 19, 19, 19, 19, 19, 19, 19, 18,
+ 18, 18, 18, 18, 18, 17, 17, 17,
+ 17, 17, 17, 17, 16, 16, 16, 16,
+ 16, 16, 16, 16, 15, 15, 15, 15,
+ 15, 15, 15, 15, 14, 14, 14, 14,
+ 14, 14, 14, 14, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 12, 12, 12,
+ 12, 12, 12, 12, 12, 12, 12, 11,
+ 11, 11, 11, 11, 11, 11, 11, 11,
+ 11, 11, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8,
+ 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 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, 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, 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,
+};
Added: trunk/src/host/qemu-neo1973/target-ppc/mfrom_table_gen.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-ppc/mfrom_table_gen.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/target-ppc/mfrom_table_gen.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,33 @@
+#define _GNU_SOURCE
+#include <stdint.h>
+#include <stdio.h>
+#include <math.h>
+
+int main (void)
+{
+ double d;
+ uint8_t n;
+ int i;
+
+ printf("static const uint8_t mfrom_ROM_table[602] =\n{\n ");
+ for (i = 0; i < 602; i++) {
+ /* Extremly decomposed:
+ * -T0 / 256
+ * T0 = 256 * log10(10 + 1.0) + 0.5
+ */
+ d = -i;
+ d /= 256.0;
+ d = exp10(d);
+ d += 1.0;
+ d = log10(d);
+ d *= 256;
+ d += 0.5;
+ n = d;
+ printf("%3d, ", n);
+ if ((i & 7) == 7)
+ printf("\n ");
+ }
+ printf("\n};\n");
+
+ return 0;
+}
Modified: trunk/src/host/qemu-neo1973/target-ppc/op.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-ppc/op.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/target-ppc/op.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -1,7 +1,7 @@
/*
* PowerPC emulation micro-operations for qemu.
*
- * Copyright (c) 2003-2005 Jocelyn Mayer
+ * Copyright (c) 2003-2007 Jocelyn Mayer
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -22,17 +22,17 @@
#include "config.h"
#include "exec.h"
+#include "op_helper.h"
+/* XXX: this is to be suppressed */
#define regs (env)
-#define Ts0 (int32_t)T0
-#define Ts1 (int32_t)T1
-#define Ts2 (int32_t)T2
#define FT0 (env->ft0)
#define FT1 (env->ft1)
#define FT2 (env->ft2)
-#define PPC_OP(name) void glue(op_, name)(void)
+/* XXX: this is to be suppressed... */
+#define PPC_OP(name) void OPPROTO glue(op_, name)(void)
#define REG 0
#include "op_template.h"
@@ -130,35 +130,18 @@
#define REG 31
#include "op_template.h"
-/* PowerPC state maintenance operations */
-/* set_Rc0 */
-PPC_OP(set_Rc0)
-{
- uint32_t tmp;
- if (Ts0 < 0) {
- tmp = 0x08;
- } else if (Ts0 > 0) {
- tmp = 0x04;
- } else {
- tmp = 0x02;
- }
- tmp |= xer_ov;
- env->crf[0] = tmp;
- RETURN();
-}
-
-/* reset_Rc0 */
-PPC_OP(reset_Rc0)
+void OPPROTO op_print_mem_EA (void)
{
- env->crf[0] = 0x02 | xer_ov;
+ do_print_mem_EA(T0);
RETURN();
}
-/* set_Rc0_1 */
-PPC_OP(set_Rc0_1)
+/* PowerPC state maintenance operations */
+/* set_Rc0 */
+PPC_OP(set_Rc0)
{
- env->crf[0] = 0x04 | xer_ov;
+ env->crf[0] = T0 | xer_ov;
RETURN();
}
@@ -170,70 +153,85 @@
}
/* Constants load */
-PPC_OP(set_T0)
+void OPPROTO op_reset_T0 (void)
{
- T0 = PARAM(1);
+ T0 = 0;
RETURN();
}
-PPC_OP(set_T1)
+PPC_OP(set_T0)
{
- T1 = PARAM(1);
+ T0 = (uint32_t)PARAM1;
RETURN();
}
-PPC_OP(set_T2)
+#if defined(TARGET_PPC64)
+void OPPROTO op_set_T0_64 (void)
{
- T2 = PARAM(1);
+ T0 = ((uint64_t)PARAM1 << 32) | (uint64_t)PARAM2;
RETURN();
}
+#endif
-/* Generate exceptions */
-PPC_OP(raise_exception_err)
+PPC_OP(set_T1)
{
- do_raise_exception_err(PARAM(1), PARAM(2));
+ T1 = (uint32_t)PARAM1;
+ RETURN();
}
-PPC_OP(raise_exception)
+#if defined(TARGET_PPC64)
+void OPPROTO op_set_T1_64 (void)
{
- do_raise_exception(PARAM(1));
+ T1 = ((uint64_t)PARAM1 << 32) | (uint64_t)PARAM2;
+ RETURN();
}
+#endif
-PPC_OP(update_nip)
+#if 0 // unused
+PPC_OP(set_T2)
{
- env->nip = PARAM(1);
+ T2 = PARAM(1);
+ RETURN();
}
+#endif
-PPC_OP(debug)
+void OPPROTO op_move_T1_T0 (void)
{
- do_raise_exception(EXCP_DEBUG);
+ T1 = T0;
+ RETURN();
}
-/* Segment registers load and store with immediate index */
-PPC_OP(load_srin)
+void OPPROTO op_move_T2_T0 (void)
{
- T0 = regs->sr[T1 >> 28];
+ T2 = T0;
RETURN();
}
-PPC_OP(store_srin)
+/* Generate exceptions */
+PPC_OP(raise_exception_err)
{
- do_store_sr(env, ((uint32_t)T1 >> 28), T0);
- RETURN();
+ do_raise_exception_err(PARAM(1), PARAM(2));
}
-PPC_OP(load_sdr1)
+PPC_OP(update_nip)
{
- T0 = regs->sdr1;
+ env->nip = (uint32_t)PARAM1;
RETURN();
}
-PPC_OP(store_sdr1)
+#if defined(TARGET_PPC64)
+void OPPROTO op_update_nip_64 (void)
{
- do_store_sdr1(env, T0);
+ env->nip = ((uint64_t)PARAM1 << 32) | (uint64_t)PARAM2;
RETURN();
}
+#endif
+PPC_OP(debug)
+{
+ do_raise_exception(EXCP_DEBUG);
+}
+
PPC_OP(exit_tb)
{
EXIT_TB();
@@ -242,26 +240,43 @@
/* Load/store special registers */
PPC_OP(load_cr)
{
- T0 = do_load_cr(env);
+ do_load_cr();
RETURN();
}
PPC_OP(store_cr)
{
- do_store_cr(env, T0, PARAM(1));
+ do_store_cr(PARAM(1));
RETURN();
}
+void OPPROTO op_load_cro (void)
+{
+ T0 = env->crf[PARAM1];
+ RETURN();
+}
+
+void OPPROTO op_store_cro (void)
+{
+ env->crf[PARAM1] = T0;
+ RETURN();
+}
+
PPC_OP(load_xer_cr)
{
T0 = (xer_so << 3) | (xer_ov << 2) | (xer_ca << 1);
RETURN();
}
-PPC_OP(clear_xer_cr)
+PPC_OP(clear_xer_ov)
{
xer_so = 0;
xer_ov = 0;
+ RETURN();
+}
+
+PPC_OP(clear_xer_ca)
+{
xer_ca = 0;
RETURN();
}
@@ -272,18 +287,64 @@
RETURN();
}
+void OPPROTO op_store_xer_bc (void)
+{
+ xer_bc = T0;
+ RETURN();
+}
+
PPC_OP(load_xer)
{
- T0 = do_load_xer(env);
+ do_load_xer();
RETURN();
}
PPC_OP(store_xer)
{
- do_store_xer(env, T0);
+ do_store_xer();
RETURN();
}
+#if !defined(CONFIG_USER_ONLY)
+/* Segment registers load and store */
+PPC_OP(load_sr)
+{
+ T0 = regs->sr[T1];
+ RETURN();
+}
+
+PPC_OP(store_sr)
+{
+ do_store_sr(env, T1, T0);
+ RETURN();
+}
+
+PPC_OP(load_sdr1)
+{
+ T0 = regs->sdr1;
+ RETURN();
+}
+
+PPC_OP(store_sdr1)
+{
+ do_store_sdr1(env, T0);
+ RETURN();
+}
+
+#if defined (TARGET_PPC64)
+void OPPROTO op_load_asr (void)
+{
+ T0 = env->asr;
+ RETURN();
+}
+
+void OPPROTO op_store_asr (void)
+{
+ ppc_store_asr(env, T0);
+ RETURN();
+}
+#endif
+
PPC_OP(load_msr)
{
T0 = do_load_msr(env);
@@ -296,19 +357,46 @@
RETURN();
}
+#if defined (TARGET_PPC64)
+void OPPROTO op_store_msr_32 (void)
+{
+ ppc_store_msr_32(env, T0);
+ RETURN();
+}
+#endif
+#endif
+
/* SPR */
-PPC_OP(load_spr)
+void OPPROTO op_load_spr (void)
{
- T0 = regs->spr[PARAM(1)];
+ T0 = env->spr[PARAM1];
RETURN();
}
-PPC_OP(store_spr)
+void OPPROTO op_store_spr (void)
{
- regs->spr[PARAM(1)] = T0;
+ env->spr[PARAM1] = T0;
RETURN();
}
+void OPPROTO op_load_dump_spr (void)
+{
+ T0 = ppc_load_dump_spr(PARAM1);
+ RETURN();
+}
+
+void OPPROTO op_store_dump_spr (void)
+{
+ ppc_store_dump_spr(PARAM1, T0);
+ RETURN();
+}
+
+void OPPROTO op_mask_spr (void)
+{
+ env->spr[PARAM1] &= ~T0;
+ RETURN();
+}
+
PPC_OP(load_lr)
{
T0 = regs->lr;
@@ -345,6 +433,7 @@
RETURN();
}
+#if !defined(CONFIG_USER_ONLY)
PPC_OP(store_tbl)
{
cpu_ppc_store_tbl(regs, T0);
@@ -360,7 +449,8 @@
PPC_OP(load_decr)
{
T0 = cpu_ppc_load_decr(regs);
- }
+ RETURN();
+}
PPC_OP(store_decr)
{
@@ -371,15 +461,16 @@
PPC_OP(load_ibat)
{
T0 = regs->IBAT[PARAM(1)][PARAM(2)];
+ RETURN();
}
-void op_store_ibatu (void)
+void OPPROTO op_store_ibatu (void)
{
do_store_ibatu(env, PARAM1, T0);
RETURN();
}
-void op_store_ibatl (void)
+void OPPROTO op_store_ibatl (void)
{
#if 1
env->IBAT[1][PARAM1] = T0;
@@ -392,15 +483,16 @@
PPC_OP(load_dbat)
{
T0 = regs->DBAT[PARAM(1)][PARAM(2)];
+ RETURN();
}
-void op_store_dbatu (void)
+void OPPROTO op_store_dbatu (void)
{
do_store_dbatu(env, PARAM1, T0);
RETURN();
}
-void op_store_dbatl (void)
+void OPPROTO op_store_dbatl (void)
{
#if 1
env->DBAT[1][PARAM1] = T0;
@@ -409,17 +501,18 @@
#endif
RETURN();
}
+#endif /* !defined(CONFIG_USER_ONLY) */
/* FPSCR */
PPC_OP(load_fpscr)
{
- FT0 = do_load_fpscr(env);
+ do_load_fpscr();
RETURN();
}
PPC_OP(store_fpscr)
{
- do_store_fpscr(env, FT0, PARAM1);
+ do_store_fpscr(PARAM1);
RETURN();
}
@@ -444,7 +537,7 @@
PPC_OP(setcrfbit)
{
- T1 = (T1 & PARAM(1)) | (T0 << PARAM(2));
+ T1 = (T1 & PARAM(1)) | (T0 << PARAM(2));
RETURN();
}
@@ -453,9 +546,18 @@
PPC_OP(setlr)
{
- regs->lr = PARAM1;
+ regs->lr = (uint32_t)PARAM1;
+ RETURN();
}
+#if defined (TARGET_PPC64)
+void OPPROTO op_setlr_64 (void)
+{
+ regs->lr = ((uint64_t)PARAM1 << 32) | (uint64_t)PARAM2;
+ RETURN();
+}
+#endif
+
PPC_OP(goto_tb0)
{
GOTO_TB(op_goto_tb0, PARAM1, 0);
@@ -466,11 +568,20 @@
GOTO_TB(op_goto_tb1, PARAM1, 1);
}
-PPC_OP(b_T1)
+void OPPROTO op_b_T1 (void)
{
- regs->nip = T1 & ~3;
+ regs->nip = (uint32_t)(T1 & ~3);
+ RETURN();
}
+#if defined (TARGET_PPC64)
+void OPPROTO op_b_T1_64 (void)
+{
+ regs->nip = (uint64_t)(T1 & ~3);
+ RETURN();
+}
+#endif
+
PPC_OP(jz_T0)
{
if (!T0)
@@ -478,66 +589,135 @@
RETURN();
}
-PPC_OP(btest_T1)
+void OPPROTO op_btest_T1 (void)
{
if (T0) {
- regs->nip = T1 & ~3;
+ regs->nip = (uint32_t)(T1 & ~3);
} else {
- regs->nip = PARAM1;
+ regs->nip = (uint32_t)PARAM1;
}
RETURN();
}
+#if defined (TARGET_PPC64)
+void OPPROTO op_btest_T1_64 (void)
+{
+ if (T0) {
+ regs->nip = (uint64_t)(T1 & ~3);
+ } else {
+ regs->nip = ((uint64_t)PARAM1 << 32) | (uint64_t)PARAM2;
+ }
+ RETURN();
+}
+#endif
+
PPC_OP(movl_T1_ctr)
{
T1 = regs->ctr;
+ RETURN();
}
PPC_OP(movl_T1_lr)
{
T1 = regs->lr;
+ RETURN();
}
/* tests with result in T0 */
+void OPPROTO op_test_ctr (void)
+{
+ T0 = (uint32_t)regs->ctr;
+ RETURN();
+}
-PPC_OP(test_ctr)
+#if defined(TARGET_PPC64)
+void OPPROTO op_test_ctr_64 (void)
{
- T0 = regs->ctr;
+ T0 = (uint64_t)regs->ctr;
+ RETURN();
}
+#endif
-PPC_OP(test_ctr_true)
+void OPPROTO op_test_ctr_true (void)
{
- T0 = (regs->ctr != 0 && (T0 & PARAM(1)) != 0);
+ T0 = ((uint32_t)regs->ctr != 0 && (T0 & PARAM1) != 0);
+ RETURN();
}
-PPC_OP(test_ctr_false)
+#if defined(TARGET_PPC64)
+void OPPROTO op_test_ctr_true_64 (void)
{
- T0 = (regs->ctr != 0 && (T0 & PARAM(1)) == 0);
+ T0 = ((uint64_t)regs->ctr != 0 && (T0 & PARAM1) != 0);
+ RETURN();
}
+#endif
-PPC_OP(test_ctrz)
+void OPPROTO op_test_ctr_false (void)
{
- T0 = (regs->ctr == 0);
+ T0 = ((uint32_t)regs->ctr != 0 && (T0 & PARAM1) == 0);
+ RETURN();
}
-PPC_OP(test_ctrz_true)
+#if defined(TARGET_PPC64)
+void OPPROTO op_test_ctr_false_64 (void)
{
- T0 = (regs->ctr == 0 && (T0 & PARAM(1)) != 0);
+ T0 = ((uint64_t)regs->ctr != 0 && (T0 & PARAM1) == 0);
+ RETURN();
}
+#endif
-PPC_OP(test_ctrz_false)
+void OPPROTO op_test_ctrz (void)
{
- T0 = (regs->ctr == 0 && (T0 & PARAM(1)) == 0);
+ T0 = ((uint32_t)regs->ctr == 0);
+ RETURN();
}
+#if defined(TARGET_PPC64)
+void OPPROTO op_test_ctrz_64 (void)
+{
+ T0 = ((uint64_t)regs->ctr == 0);
+ RETURN();
+}
+#endif
+
+void OPPROTO op_test_ctrz_true (void)
+{
+ T0 = ((uint32_t)regs->ctr == 0 && (T0 & PARAM1) != 0);
+ RETURN();
+}
+
+#if defined(TARGET_PPC64)
+void OPPROTO op_test_ctrz_true_64 (void)
+{
+ T0 = ((uint64_t)regs->ctr == 0 && (T0 & PARAM1) != 0);
+ RETURN();
+}
+#endif
+
+void OPPROTO op_test_ctrz_false (void)
+{
+ T0 = ((uint32_t)regs->ctr == 0 && (T0 & PARAM1) == 0);
+ RETURN();
+}
+
+#if defined(TARGET_PPC64)
+void OPPROTO op_test_ctrz_false_64 (void)
+{
+ T0 = ((uint64_t)regs->ctr == 0 && (T0 & PARAM1) == 0);
+ RETURN();
+}
+#endif
+
PPC_OP(test_true)
{
T0 = (T0 & PARAM(1));
+ RETURN();
}
PPC_OP(test_false)
{
T0 = ((T0 & PARAM(1)) == 0);
+ RETURN();
}
/* CTR maintenance */
@@ -555,191 +735,296 @@
RETURN();
}
-void do_addo (void);
-void op_addo (void)
+void OPPROTO op_check_addo (void)
{
- do_addo();
+ if (likely(!(((uint32_t)T2 ^ (uint32_t)T1 ^ UINT32_MAX) &
+ ((uint32_t)T2 ^ (uint32_t)T0) & (1UL << 31)))) {
+ xer_ov = 0;
+ } else {
+ xer_so = 1;
+ xer_ov = 1;
+ }
RETURN();
}
+#if defined(TARGET_PPC64)
+void OPPROTO op_check_addo_64 (void)
+{
+ if (likely(!(((uint64_t)T2 ^ (uint64_t)T1 ^ UINT64_MAX) &
+ ((uint64_t)T2 ^ (uint64_t)T0) & (1ULL << 63)))) {
+ xer_ov = 0;
+ } else {
+ xer_so = 1;
+ xer_ov = 1;
+ }
+ RETURN();
+}
+#endif
+
/* add carrying */
-PPC_OP(addc)
+void OPPROTO op_check_addc (void)
{
- T2 = T0;
- T0 += T1;
- if (T0 < T2) {
+ if (likely((uint32_t)T0 >= (uint32_t)T2)) {
+ xer_ca = 0;
+ } else {
xer_ca = 1;
- } else {
- xer_ca = 0;
}
RETURN();
}
-void do_addco (void);
-void op_addco (void)
+#if defined(TARGET_PPC64)
+void OPPROTO op_check_addc_64 (void)
{
- do_addco();
+ if (likely((uint64_t)T0 >= (uint64_t)T2)) {
+ xer_ca = 0;
+ } else {
+ xer_ca = 1;
+ }
RETURN();
}
+#endif
/* add extended */
-void do_adde (void);
-void op_adde (void)
+void OPPROTO op_adde (void)
{
do_adde();
+ RETURN();
}
-void do_addeo (void);
-PPC_OP(addeo)
+#if defined(TARGET_PPC64)
+void OPPROTO op_adde_64 (void)
{
- do_addeo();
+ do_adde_64();
RETURN();
}
+#endif
/* add immediate */
PPC_OP(addi)
{
- T0 += PARAM(1);
+ T0 += (int32_t)PARAM(1);
RETURN();
}
-/* add immediate carrying */
-PPC_OP(addic)
+/* add to minus one extended */
+void OPPROTO op_add_me (void)
{
- T1 = T0;
- T0 += PARAM(1);
- if (T0 < T1) {
+ T0 += xer_ca + (-1);
+ if (likely((uint32_t)T1 != 0))
xer_ca = 1;
- } else {
- xer_ca = 0;
- }
RETURN();
}
-/* add to minus one extended */
-PPC_OP(addme)
+#if defined(TARGET_PPC64)
+void OPPROTO op_add_me_64 (void)
{
- T1 = T0;
T0 += xer_ca + (-1);
- if (T1 != 0)
+ if (likely((uint64_t)T1 != 0))
xer_ca = 1;
RETURN();
}
+#endif
-void do_addmeo (void);
-void op_addmeo (void)
+void OPPROTO op_addmeo (void)
{
do_addmeo();
RETURN();
}
+void OPPROTO op_addmeo_64 (void)
+{
+ do_addmeo();
+ RETURN();
+}
+
/* add to zero extended */
-PPC_OP(addze)
+void OPPROTO op_add_ze (void)
{
- T1 = T0;
T0 += xer_ca;
- if (T0 < T1) {
- xer_ca = 1;
- } else {
- xer_ca = 0;
- }
RETURN();
}
-void do_addzeo (void);
-void op_addzeo (void)
+/* divide word */
+void OPPROTO op_divw (void)
{
- do_addzeo();
+ if (unlikely(((int32_t)T0 == INT32_MIN && (int32_t)T1 == -1) ||
+ (int32_t)T1 == 0)) {
+ T0 = (int32_t)((-1) * ((uint32_t)T0 >> 31));
+ } else {
+ T0 = (int32_t)T0 / (int32_t)T1;
+ }
RETURN();
}
-/* divide word */
-PPC_OP(divw)
+#if defined(TARGET_PPC64)
+void OPPROTO op_divd (void)
{
- if ((Ts0 == INT32_MIN && Ts1 == -1) || Ts1 == 0) {
- T0 = (int32_t)((-1) * (T0 >> 31));
+ if (unlikely(((int64_t)T0 == INT64_MIN && (int64_t)T1 == -1) ||
+ (int64_t)T1 == 0)) {
+ T0 = (int64_t)((-1ULL) * ((uint64_t)T0 >> 63));
} else {
- T0 = (Ts0 / Ts1);
+ T0 = (int64_t)T0 / (int64_t)T1;
}
RETURN();
}
+#endif
-void do_divwo (void);
-void op_divwo (void)
+void OPPROTO op_divwo (void)
{
do_divwo();
RETURN();
}
+#if defined(TARGET_PPC64)
+void OPPROTO op_divdo (void)
+{
+ do_divdo();
+ RETURN();
+}
+#endif
+
/* divide word unsigned */
-PPC_OP(divwu)
+void OPPROTO op_divwu (void)
{
- if (T1 == 0) {
+ if (unlikely(T1 == 0)) {
T0 = 0;
} else {
+ T0 = (uint32_t)T0 / (uint32_t)T1;
+ }
+ RETURN();
+}
+
+#if defined(TARGET_PPC64)
+void OPPROTO op_divdu (void)
+{
+ if (unlikely(T1 == 0)) {
+ T0 = 0;
+ } else {
T0 /= T1;
}
RETURN();
}
+#endif
-void do_divwuo (void);
-void op_divwuo (void)
+void OPPROTO op_divwuo (void)
{
do_divwuo();
RETURN();
}
+#if defined(TARGET_PPC64)
+void OPPROTO op_divduo (void)
+{
+ do_divduo();
+ RETURN();
+}
+#endif
+
/* multiply high word */
-PPC_OP(mulhw)
+void OPPROTO op_mulhw (void)
{
- T0 = ((int64_t)Ts0 * (int64_t)Ts1) >> 32;
+ T0 = ((int64_t)((int32_t)T0) * (int64_t)((int32_t)T1)) >> 32;
RETURN();
}
+#if defined(TARGET_PPC64)
+void OPPROTO op_mulhd (void)
+{
+ uint64_t tl, th;
+
+ do_imul64(&tl, &th);
+ T0 = th;
+ RETURN();
+}
+#endif
+
/* multiply high word unsigned */
-PPC_OP(mulhwu)
+void OPPROTO op_mulhwu (void)
{
- T0 = ((uint64_t)T0 * (uint64_t)T1) >> 32;
+ T0 = ((uint64_t)(uint32_t)T0 * (uint64_t)(uint32_t)T1) >> 32;
RETURN();
}
+#if defined(TARGET_PPC64)
+void OPPROTO op_mulhdu (void)
+{
+ uint64_t tl, th;
+
+ do_mul64(&tl, &th);
+ T0 = th;
+ RETURN();
+}
+#endif
+
/* multiply low immediate */
PPC_OP(mulli)
{
- T0 = (Ts0 * SPARAM(1));
+ T0 = ((int32_t)T0 * (int32_t)PARAM1);
RETURN();
}
/* multiply low word */
PPC_OP(mullw)
{
+ T0 = (int32_t)(T0 * T1);
+ RETURN();
+}
+
+#if defined(TARGET_PPC64)
+void OPPROTO op_mulld (void)
+{
T0 *= T1;
RETURN();
}
+#endif
-void do_mullwo (void);
-void op_mullwo (void)
+void OPPROTO op_mullwo (void)
{
do_mullwo();
RETURN();
}
+#if defined(TARGET_PPC64)
+void OPPROTO op_mulldo (void)
+{
+ do_mulldo();
+ RETURN();
+}
+#endif
+
/* negate */
-PPC_OP(neg)
+void OPPROTO op_neg (void)
{
- if (T0 != 0x80000000) {
- T0 = -Ts0;
+ if (likely(T0 != INT32_MIN)) {
+ T0 = -(int32_t)T0;
}
RETURN();
}
-void do_nego (void);
-void op_nego (void)
+#if defined(TARGET_PPC64)
+void OPPROTO op_neg_64 (void)
{
+ if (likely(T0 != INT64_MIN)) {
+ T0 = -(int64_t)T0;
+ }
+ RETURN();
+}
+#endif
+
+void OPPROTO op_nego (void)
+{
do_nego();
RETURN();
}
+#if defined(TARGET_PPC64)
+void OPPROTO op_nego_64 (void)
+{
+ do_nego_64();
+ RETURN();
+}
+#endif
+
/* substract from */
PPC_OP(subf)
{
@@ -747,52 +1032,75 @@
RETURN();
}
-void do_subfo (void);
-void op_subfo (void)
+void OPPROTO op_check_subfo (void)
{
- do_subfo();
+ if (likely(!(((uint32_t)(~T2) ^ (uint32_t)T1 ^ UINT32_MAX) &
+ ((uint32_t)(~T2) ^ (uint32_t)T0) & (1UL << 31)))) {
+ xer_ov = 0;
+ } else {
+ xer_so = 1;
+ xer_ov = 1;
+ }
RETURN();
}
+#if defined(TARGET_PPC64)
+void OPPROTO op_check_subfo_64 (void)
+{
+ if (likely(!(((uint64_t)(~T2) ^ (uint64_t)T1 ^ UINT64_MAX) &
+ ((uint64_t)(~T2) ^ (uint64_t)T0) & (1ULL << 63)))) {
+ xer_ov = 0;
+ } else {
+ xer_so = 1;
+ xer_ov = 1;
+ }
+ RETURN();
+}
+#endif
+
/* substract from carrying */
-PPC_OP(subfc)
+void OPPROTO op_check_subfc (void)
{
- T0 = T1 - T0;
- if (T0 <= T1) {
+ if (likely((uint32_t)T0 > (uint32_t)T1)) {
+ xer_ca = 0;
+ } else {
xer_ca = 1;
- } else {
- xer_ca = 0;
}
RETURN();
}
-void do_subfco (void);
-void op_subfco (void)
+#if defined(TARGET_PPC64)
+void OPPROTO op_check_subfc_64 (void)
{
- do_subfco();
+ if (likely((uint64_t)T0 > (uint64_t)T1)) {
+ xer_ca = 0;
+ } else {
+ xer_ca = 1;
+ }
RETURN();
}
+#endif
/* substract from extended */
-void do_subfe (void);
-void op_subfe (void)
+void OPPROTO op_subfe (void)
{
do_subfe();
RETURN();
}
-void do_subfeo (void);
-PPC_OP(subfeo)
+#if defined(TARGET_PPC64)
+void OPPROTO op_subfe_64 (void)
{
- do_subfeo();
+ do_subfe_64();
RETURN();
}
+#endif
/* substract from immediate carrying */
-PPC_OP(subfic)
+void OPPROTO op_subfic (void)
{
- T0 = PARAM(1) + ~T0 + 1;
- if (T0 <= PARAM(1)) {
+ T0 = (int32_t)PARAM1 + ~T0 + 1;
+ if ((uint32_t)T0 <= (uint32_t)PARAM1) {
xer_ca = 1;
} else {
xer_ca = 0;
@@ -800,29 +1108,58 @@
RETURN();
}
+#if defined(TARGET_PPC64)
+void OPPROTO op_subfic_64 (void)
+{
+ T0 = PARAM1 + ~T0 + 1;
+ if ((uint64_t)T0 <= (uint64_t)PARAM1) {
+ xer_ca = 1;
+ } else {
+ xer_ca = 0;
+ }
+ RETURN();
+}
+#endif
+
/* substract from minus one extended */
-PPC_OP(subfme)
+void OPPROTO op_subfme (void)
{
T0 = ~T0 + xer_ca - 1;
+ if (likely((uint32_t)T0 != (uint32_t)-1))
+ xer_ca = 1;
+ RETURN();
+}
- if (T0 != -1)
+#if defined(TARGET_PPC64)
+void OPPROTO op_subfme_64 (void)
+{
+ T0 = ~T0 + xer_ca - 1;
+ if (likely((uint64_t)T0 != (uint64_t)-1))
xer_ca = 1;
RETURN();
}
+#endif
-void do_subfmeo (void);
-void op_subfmeo (void)
+void OPPROTO op_subfmeo (void)
{
do_subfmeo();
RETURN();
}
+#if defined(TARGET_PPC64)
+void OPPROTO op_subfmeo_64 (void)
+{
+ do_subfmeo_64();
+ RETURN();
+}
+#endif
+
/* substract from zero extended */
-PPC_OP(subfze)
+void OPPROTO op_subfze (void)
{
T1 = ~T0;
T0 = T1 + xer_ca;
- if (T0 < T1) {
+ if ((uint32_t)T0 < (uint32_t)T1) {
xer_ca = 1;
} else {
xer_ca = 0;
@@ -830,20 +1167,41 @@
RETURN();
}
-void do_subfzeo (void);
-void op_subfzeo (void)
+#if defined(TARGET_PPC64)
+void OPPROTO op_subfze_64 (void)
{
+ T1 = ~T0;
+ T0 = T1 + xer_ca;
+ if ((uint64_t)T0 < (uint64_t)T1) {
+ xer_ca = 1;
+ } else {
+ xer_ca = 0;
+ }
+ RETURN();
+}
+#endif
+
+void OPPROTO op_subfzeo (void)
+{
do_subfzeo();
RETURN();
}
+#if defined(TARGET_PPC64)
+void OPPROTO op_subfzeo_64 (void)
+{
+ do_subfzeo_64();
+ RETURN();
+}
+#endif
+
/*** Integer comparison ***/
/* compare */
-PPC_OP(cmp)
+void OPPROTO op_cmp (void)
{
- if (Ts0 < Ts1) {
+ if ((int32_t)T0 < (int32_t)T1) {
T0 = 0x08;
- } else if (Ts0 > Ts1) {
+ } else if ((int32_t)T0 > (int32_t)T1) {
T0 = 0x04;
} else {
T0 = 0x02;
@@ -851,12 +1209,26 @@
RETURN();
}
+#if defined(TARGET_PPC64)
+void OPPROTO op_cmp_64 (void)
+{
+ if ((int64_t)T0 < (int64_t)T1) {
+ T0 = 0x08;
+ } else if ((int64_t)T0 > (int64_t)T1) {
+ T0 = 0x04;
+ } else {
+ T0 = 0x02;
+ }
+ RETURN();
+}
+#endif
+
/* compare immediate */
-PPC_OP(cmpi)
+void OPPROTO op_cmpi (void)
{
- if (Ts0 < SPARAM(1)) {
+ if ((int32_t)T0 < (int32_t)PARAM1) {
T0 = 0x08;
- } else if (Ts0 > SPARAM(1)) {
+ } else if ((int32_t)T0 > (int32_t)PARAM1) {
T0 = 0x04;
} else {
T0 = 0x02;
@@ -864,12 +1236,26 @@
RETURN();
}
+#if defined(TARGET_PPC64)
+void OPPROTO op_cmpi_64 (void)
+{
+ if ((int64_t)T0 < (int64_t)((int32_t)PARAM1)) {
+ T0 = 0x08;
+ } else if ((int64_t)T0 > (int64_t)((int32_t)PARAM1)) {
+ T0 = 0x04;
+ } else {
+ T0 = 0x02;
+ }
+ RETURN();
+}
+#endif
+
/* compare logical */
-PPC_OP(cmpl)
+void OPPROTO op_cmpl (void)
{
- if (T0 < T1) {
+ if ((uint32_t)T0 < (uint32_t)T1) {
T0 = 0x08;
- } else if (T0 > T1) {
+ } else if ((uint32_t)T0 > (uint32_t)T1) {
T0 = 0x04;
} else {
T0 = 0x02;
@@ -877,12 +1263,26 @@
RETURN();
}
+#if defined(TARGET_PPC64)
+void OPPROTO op_cmpl_64 (void)
+{
+ if ((uint64_t)T0 < (uint64_t)T1) {
+ T0 = 0x08;
+ } else if ((uint64_t)T0 > (uint64_t)T1) {
+ T0 = 0x04;
+ } else {
+ T0 = 0x02;
+ }
+ RETURN();
+}
+#endif
+
/* compare logical immediate */
-PPC_OP(cmpli)
+void OPPROTO op_cmpli (void)
{
- if (T0 < PARAM(1)) {
+ if ((uint32_t)T0 < (uint32_t)PARAM1) {
T0 = 0x08;
- } else if (T0 > PARAM(1)) {
+ } else if ((uint32_t)T0 > (uint32_t)PARAM1) {
T0 = 0x04;
} else {
T0 = 0x02;
@@ -890,6 +1290,43 @@
RETURN();
}
+#if defined(TARGET_PPC64)
+void OPPROTO op_cmpli_64 (void)
+{
+ if ((uint64_t)T0 < (uint64_t)PARAM1) {
+ T0 = 0x08;
+ } else if ((uint64_t)T0 > (uint64_t)PARAM1) {
+ T0 = 0x04;
+ } else {
+ T0 = 0x02;
+ }
+ RETURN();
+}
+#endif
+
+void OPPROTO op_isel (void)
+{
+ if (T0)
+ T0 = T1;
+ else
+ T0 = T2;
+ RETURN();
+}
+
+void OPPROTO op_popcntb (void)
+{
+ do_popcntb();
+ RETURN();
+}
+
+#if defined(TARGET_PPC64)
+void OPPROTO op_popcntb_64 (void)
+{
+ do_popcntb_64();
+ RETURN();
+}
+#endif
+
/*** Integer logical ***/
/* and */
PPC_OP(and)
@@ -906,21 +1343,33 @@
}
/* andi. */
-PPC_OP(andi_)
+void OPPROTO op_andi_T0 (void)
{
T0 &= PARAM(1);
RETURN();
}
+void OPPROTO op_andi_T1 (void)
+{
+ T1 &= PARAM1;
+ RETURN();
+}
+
/* count leading zero */
-PPC_OP(cntlzw)
+void OPPROTO op_cntlzw (void)
{
- T1 = T0;
- for (T0 = 32; T1 > 0; T0--)
- T1 = T1 >> 1;
+ T0 = _do_cntlzw(T0);
RETURN();
}
+#if defined(TARGET_PPC64)
+void OPPROTO op_cntlzd (void)
+{
+ T0 = _do_cntlzd(T0);
+ RETURN();
+}
+#endif
+
/* eqv */
PPC_OP(eqv)
{
@@ -929,19 +1378,35 @@
}
/* extend sign byte */
-PPC_OP(extsb)
+void OPPROTO op_extsb (void)
{
- T0 = (int32_t)((int8_t)(Ts0));
+#if defined (TARGET_PPC64)
+ T0 = (int64_t)((int8_t)T0);
+#else
+ T0 = (int32_t)((int8_t)T0);
+#endif
RETURN();
}
/* extend sign half word */
-PPC_OP(extsh)
+void OPPROTO op_extsh (void)
{
- T0 = (int32_t)((int16_t)(Ts0));
+#if defined (TARGET_PPC64)
+ T0 = (int64_t)((int16_t)T0);
+#else
+ T0 = (int32_t)((int16_t)T0);
+#endif
RETURN();
}
+#if defined (TARGET_PPC64)
+void OPPROTO op_extsw (void)
+{
+ T0 = (int64_t)((int32_t)T0);
+ RETURN();
+}
+#endif
+
/* nand */
PPC_OP(nand)
{
@@ -992,113 +1457,196 @@
}
/*** Integer rotate ***/
-/* rotate left word immediate then mask insert */
-PPC_OP(rlwimi)
+void OPPROTO op_rotl32_T0_T1 (void)
{
- T0 = (rotl(T0, PARAM(1)) & PARAM(2)) | (T1 & PARAM(3));
+ T0 = rotl32(T0, T1 & 0x1F);
RETURN();
}
-/* rotate left immediate then and with mask insert */
-PPC_OP(rotlwi)
+void OPPROTO op_rotli32_T0 (void)
{
- T0 = rotl(T0, PARAM(1));
+ T0 = rotl32(T0, PARAM1);
RETURN();
}
-PPC_OP(slwi)
+#if defined(TARGET_PPC64)
+void OPPROTO op_rotl64_T0_T1 (void)
{
- T0 = T0 << PARAM(1);
+ T0 = rotl64(T0, T1 & 0x3F);
RETURN();
}
-PPC_OP(srwi)
+void OPPROTO op_rotli64_T0 (void)
{
- T0 = T0 >> PARAM(1);
+ T0 = rotl64(T0, PARAM1);
RETURN();
}
+#endif
-/* rotate left word then and with mask insert */
-PPC_OP(rlwinm)
+/*** Integer shift ***/
+/* shift left word */
+void OPPROTO op_slw (void)
{
- T0 = rotl(T0, PARAM(1)) & PARAM(2);
+ if (T1 & 0x20) {
+ T0 = 0;
+ } else {
+ T0 = (uint32_t)(T0 << T1);
+ }
RETURN();
}
-PPC_OP(rotl)
+#if defined(TARGET_PPC64)
+void OPPROTO op_sld (void)
{
- T0 = rotl(T0, T1);
+ if (T1 & 0x40) {
+ T0 = 0;
+ } else {
+ T0 = T0 << T1;
+ }
RETURN();
}
+#endif
-PPC_OP(rlwnm)
+/* shift right algebraic word */
+void OPPROTO op_sraw (void)
{
- T0 = rotl(T0, T1) & PARAM(1);
+ do_sraw();
RETURN();
}
-/*** Integer shift ***/
-/* shift left word */
-PPC_OP(slw)
+#if defined(TARGET_PPC64)
+void OPPROTO op_srad (void)
{
- if (T1 & 0x20) {
- T0 = 0;
- } else {
- T0 = T0 << T1;
- }
+ do_srad();
RETURN();
}
+#endif
-/* shift right algebraic word */
-void op_sraw (void)
+/* shift right algebraic word immediate */
+void OPPROTO op_srawi (void)
{
- do_sraw();
+ uint32_t mask = (uint32_t)PARAM2;
+
+ T0 = (int32_t)T0 >> PARAM1;
+ if ((int32_t)T1 < 0 && (T1 & mask) != 0) {
+ xer_ca = 1;
+ } else {
+ xer_ca = 0;
+ }
RETURN();
}
-/* shift right algebraic word immediate */
-PPC_OP(srawi)
+#if defined(TARGET_PPC64)
+void OPPROTO op_sradi (void)
{
- T1 = T0;
- T0 = (Ts0 >> PARAM(1));
- if (Ts1 < 0 && (Ts1 & PARAM(2)) != 0) {
+ uint64_t mask = ((uint64_t)PARAM2 << 32) | (uint64_t)PARAM3;
+
+ T0 = (int64_t)T0 >> PARAM1;
+ if ((int64_t)T1 < 0 && ((uint64_t)T1 & mask) != 0) {
xer_ca = 1;
} else {
xer_ca = 0;
}
RETURN();
}
+#endif
/* shift right word */
-PPC_OP(srw)
+void OPPROTO op_srw (void)
{
if (T1 & 0x20) {
T0 = 0;
} else {
- T0 = T0 >> T1;
+ T0 = (uint32_t)T0 >> T1;
}
RETURN();
}
+#if defined(TARGET_PPC64)
+void OPPROTO op_srd (void)
+{
+ if (T1 & 0x40) {
+ T0 = 0;
+ } else {
+ T0 = (uint64_t)T0 >> T1;
+ }
+ RETURN();
+}
+#endif
+
+void OPPROTO op_sl_T0_T1 (void)
+{
+ T0 = T0 << T1;
+ RETURN();
+}
+
+void OPPROTO op_sli_T0 (void)
+{
+ T0 = T0 << PARAM1;
+ RETURN();
+}
+
+void OPPROTO op_srl_T0_T1 (void)
+{
+ T0 = (uint32_t)T0 >> T1;
+ RETURN();
+}
+
+#if defined(TARGET_PPC64)
+void OPPROTO op_srl_T0_T1_64 (void)
+{
+ T0 = (uint32_t)T0 >> T1;
+ RETURN();
+}
+#endif
+
+void OPPROTO op_srli_T0 (void)
+{
+ T0 = (uint32_t)T0 >> PARAM1;
+ RETURN();
+}
+
+#if defined(TARGET_PPC64)
+void OPPROTO op_srli_T0_64 (void)
+{
+ T0 = (uint64_t)T0 >> PARAM1;
+ RETURN();
+}
+#endif
+
+void OPPROTO op_srli_T1 (void)
+{
+ T1 = (uint32_t)T1 >> PARAM1;
+ RETURN();
+}
+
+#if defined(TARGET_PPC64)
+void OPPROTO op_srli_T1_64 (void)
+{
+ T1 = (uint64_t)T1 >> PARAM1;
+ RETURN();
+}
+#endif
+
/*** Floating-Point arithmetic ***/
/* fadd - fadd. */
PPC_OP(fadd)
{
- FT0 += FT1;
+ FT0 = float64_add(FT0, FT1, &env->fp_status);
RETURN();
}
/* fsub - fsub. */
PPC_OP(fsub)
{
- FT0 -= FT1;
+ FT0 = float64_sub(FT0, FT1, &env->fp_status);
RETURN();
}
/* fmul - fmul. */
PPC_OP(fmul)
{
- FT0 *= FT1;
+ FT0 = float64_mul(FT0, FT1, &env->fp_status);
RETURN();
}
@@ -1141,14 +1689,24 @@
/* fmadd - fmadd. */
PPC_OP(fmadd)
{
- FT0 = (FT0 * FT1) + FT2;
+#if USE_PRECISE_EMULATION
+ do_fmadd();
+#else
+ FT0 = float64_mul(FT0, FT1, &env->fp_status);
+ FT0 = float64_add(FT0, FT2, &env->fp_status);
+#endif
RETURN();
}
/* fmsub - fmsub. */
PPC_OP(fmsub)
{
- FT0 = (FT0 * FT1) - FT2;
+#if USE_PRECISE_EMULATION
+ do_fmsub();
+#else
+ FT0 = float64_mul(FT0, FT1, &env->fp_status);
+ FT0 = float64_sub(FT0, FT2, &env->fp_status);
+#endif
RETURN();
}
@@ -1170,7 +1728,7 @@
/* frsp - frsp. */
PPC_OP(frsp)
{
- FT0 = (float)FT0;
+ FT0 = float64_to_float32(FT0, &env->fp_status);
RETURN();
}
@@ -1188,7 +1746,29 @@
RETURN();
}
+#if defined(TARGET_PPC64)
+/* fcfid - fcfid. */
+PPC_OP(fcfid)
+{
+ do_fcfid();
+ RETURN();
+}
+/* fctid - fctid. */
+PPC_OP(fctid)
+{
+ do_fctid();
+ RETURN();
+}
+
+/* fctidz - fctidz. */
+PPC_OP(fctidz)
+{
+ do_fctidz();
+ RETURN();
+}
+#endif
+
/*** Floating-Point compare ***/
/* fcmpu */
PPC_OP(fcmpu)
@@ -1229,52 +1809,67 @@
/* Load and store */
#define MEMSUFFIX _raw
+#include "op_helper.h"
#include "op_mem.h"
#if !defined(CONFIG_USER_ONLY)
#define MEMSUFFIX _user
+#include "op_helper.h"
#include "op_mem.h"
-
#define MEMSUFFIX _kernel
+#include "op_helper.h"
#include "op_mem.h"
#endif
/* Special op to check and maybe clear reservation */
-PPC_OP(check_reservation)
+void OPPROTO op_check_reservation (void)
{
if ((uint32_t)env->reserve == (uint32_t)(T0 & ~0x00000003))
env->reserve = -1;
RETURN();
}
+#if defined(TARGET_PPC64)
+void OPPROTO op_check_reservation_64 (void)
+{
+ if ((uint64_t)env->reserve == (uint64_t)(T0 & ~0x00000003))
+ env->reserve = -1;
+ RETURN();
+}
+#endif
+
/* Return from interrupt */
-void do_rfi (void);
-void op_rfi (void)
+#if !defined(CONFIG_USER_ONLY)
+void OPPROTO op_rfi (void)
{
do_rfi();
RETURN();
}
-/* Trap word */
-void do_tw (uint32_t cmp, int flags);
-void op_tw (void)
+#if defined(TARGET_PPC64)
+void OPPROTO op_rfid (void)
{
- do_tw(T1, PARAM(1));
+ do_rfid();
RETURN();
}
+#endif
+#endif
-void op_twi (void)
+/* Trap word */
+void OPPROTO op_tw (void)
{
- do_tw(PARAM(1), PARAM(2));
+ do_tw(PARAM1);
RETURN();
}
-/* Instruction cache block invalidate */
-PPC_OP(icbi)
+#if defined(TARGET_PPC64)
+void OPPROTO op_td (void)
{
- do_icbi();
+ do_td(PARAM1);
RETURN();
}
+#endif
+#if !defined(CONFIG_USER_ONLY)
/* tlbia */
PPC_OP(tlbia)
{
@@ -1283,14 +1878,1324 @@
}
/* tlbie */
-PPC_OP(tlbie)
+void OPPROTO op_tlbie (void)
{
do_tlbie();
RETURN();
}
-void op_store_pir (void)
+#if defined(TARGET_PPC64)
+void OPPROTO op_tlbie_64 (void)
{
+ do_tlbie_64();
+ RETURN();
+}
+#endif
+
+#if defined(TARGET_PPC64)
+void OPPROTO op_slbia (void)
+{
+ do_slbia();
+ RETURN();
+}
+
+void OPPROTO op_slbie (void)
+{
+ do_slbie();
+ RETURN();
+}
+#endif
+#endif
+
+/* PowerPC 602/603/755 software TLB load instructions */
+#if !defined(CONFIG_USER_ONLY)
+void OPPROTO op_6xx_tlbld (void)
+{
+ do_load_6xx_tlb(0);
+ RETURN();
+}
+
+void OPPROTO op_6xx_tlbli (void)
+{
+ do_load_6xx_tlb(1);
+ RETURN();
+}
+#endif
+
+/* 601 specific */
+void OPPROTO op_load_601_rtcl (void)
+{
+ T0 = cpu_ppc601_load_rtcl(env);
+ RETURN();
+}
+
+void OPPROTO op_load_601_rtcu (void)
+{
+ T0 = cpu_ppc601_load_rtcu(env);
+ RETURN();
+}
+
+#if !defined(CONFIG_USER_ONLY)
+void OPPROTO op_store_601_rtcl (void)
+{
+ cpu_ppc601_store_rtcl(env, T0);
+ RETURN();
+}
+
+void OPPROTO op_store_601_rtcu (void)
+{
+ cpu_ppc601_store_rtcu(env, T0);
+ RETURN();
+}
+
+void OPPROTO op_load_601_bat (void)
+{
+ T0 = env->IBAT[PARAM1][PARAM2];
+ RETURN();
+}
+#endif /* !defined(CONFIG_USER_ONLY) */
+
+/* 601 unified BATs store.
+ * To avoid using specific MMU code for 601, we store BATs in
+ * IBAT and DBAT simultaneously, then emulate unified BATs.
+ */
+#if !defined(CONFIG_USER_ONLY)
+void OPPROTO op_store_601_batl (void)
+{
+ int nr = PARAM1;
+
+ env->IBAT[1][nr] = T0;
+ env->DBAT[1][nr] = T0;
+ RETURN();
+}
+
+void OPPROTO op_store_601_batu (void)
+{
+ do_store_601_batu(PARAM1);
+ RETURN();
+}
+#endif /* !defined(CONFIG_USER_ONLY) */
+
+/* PowerPC 601 specific instructions (POWER bridge) */
+/* XXX: those micro-ops need tests ! */
+void OPPROTO op_POWER_abs (void)
+{
+ if (T0 == INT32_MIN)
+ T0 = INT32_MAX;
+ else if (T0 < 0)
+ T0 = -T0;
+ RETURN();
+}
+
+void OPPROTO op_POWER_abso (void)
+{
+ do_POWER_abso();
+ RETURN();
+}
+
+void OPPROTO op_POWER_clcs (void)
+{
+ do_POWER_clcs();
+ RETURN();
+}
+
+void OPPROTO op_POWER_div (void)
+{
+ do_POWER_div();
+ RETURN();
+}
+
+void OPPROTO op_POWER_divo (void)
+{
+ do_POWER_divo();
+ RETURN();
+}
+
+void OPPROTO op_POWER_divs (void)
+{
+ do_POWER_divs();
+ RETURN();
+}
+
+void OPPROTO op_POWER_divso (void)
+{
+ do_POWER_divso();
+ RETURN();
+}
+
+void OPPROTO op_POWER_doz (void)
+{
+ if ((int32_t)T1 > (int32_t)T0)
+ T0 = T1 - T0;
+ else
+ T0 = 0;
+ RETURN();
+}
+
+void OPPROTO op_POWER_dozo (void)
+{
+ do_POWER_dozo();
+ RETURN();
+}
+
+void OPPROTO op_load_xer_cmp (void)
+{
+ T2 = xer_cmp;
+ RETURN();
+}
+
+void OPPROTO op_POWER_maskg (void)
+{
+ do_POWER_maskg();
+ RETURN();
+}
+
+void OPPROTO op_POWER_maskir (void)
+{
+ T0 = (T0 & ~T2) | (T1 & T2);
+ RETURN();
+}
+
+void OPPROTO op_POWER_mul (void)
+{
+ uint64_t tmp;
+
+ tmp = (uint64_t)T0 * (uint64_t)T1;
+ env->spr[SPR_MQ] = tmp >> 32;
+ T0 = tmp;
+ RETURN();
+}
+
+void OPPROTO op_POWER_mulo (void)
+{
+ do_POWER_mulo();
+ RETURN();
+}
+
+void OPPROTO op_POWER_nabs (void)
+{
+ if (T0 > 0)
+ T0 = -T0;
+ RETURN();
+}
+
+void OPPROTO op_POWER_nabso (void)
+{
+ /* nabs never overflows */
+ if (T0 > 0)
+ T0 = -T0;
+ xer_ov = 0;
+ RETURN();
+}
+
+/* XXX: factorise POWER rotates... */
+void OPPROTO op_POWER_rlmi (void)
+{
+ T0 = rotl32(T0, T2) & PARAM1;
+ T0 |= T1 & PARAM2;
+ RETURN();
+}
+
+void OPPROTO op_POWER_rrib (void)
+{
+ T2 &= 0x1FUL;
+ T0 = rotl32(T0 & INT32_MIN, T2);
+ T0 |= T1 & ~rotl32(INT32_MIN, T2);
+ RETURN();
+}
+
+void OPPROTO op_POWER_sle (void)
+{
+ T1 &= 0x1FUL;
+ env->spr[SPR_MQ] = rotl32(T0, T1);
+ T0 = T0 << T1;
+ RETURN();
+}
+
+void OPPROTO op_POWER_sleq (void)
+{
+ uint32_t tmp = env->spr[SPR_MQ];
+
+ T1 &= 0x1FUL;
+ env->spr[SPR_MQ] = rotl32(T0, T1);
+ T0 = T0 << T1;
+ T0 |= tmp >> (32 - T1);
+ RETURN();
+}
+
+void OPPROTO op_POWER_sllq (void)
+{
+ uint32_t msk = -1;
+
+ msk = msk << (T1 & 0x1FUL);
+ if (T1 & 0x20UL)
+ msk = ~msk;
+ T1 &= 0x1FUL;
+ T0 = (T0 << T1) & msk;
+ T0 |= env->spr[SPR_MQ] & ~msk;
+ RETURN();
+}
+
+void OPPROTO op_POWER_slq (void)
+{
+ uint32_t msk = -1, tmp;
+
+ msk = msk << (T1 & 0x1FUL);
+ if (T1 & 0x20UL)
+ msk = ~msk;
+ T1 &= 0x1FUL;
+ tmp = rotl32(T0, T1);
+ T0 = tmp & msk;
+ env->spr[SPR_MQ] = tmp;
+ RETURN();
+}
+
+void OPPROTO op_POWER_sraq (void)
+{
+ env->spr[SPR_MQ] = rotl32(T0, 32 - (T1 & 0x1FUL));
+ if (T1 & 0x20UL)
+ T0 = -1L;
+ else
+ T0 = (int32_t)T0 >> T1;
+ RETURN();
+}
+
+void OPPROTO op_POWER_sre (void)
+{
+ T1 &= 0x1FUL;
+ env->spr[SPR_MQ] = rotl32(T0, 32 - T1);
+ T0 = (int32_t)T0 >> T1;
+ RETURN();
+}
+
+void OPPROTO op_POWER_srea (void)
+{
+ T1 &= 0x1FUL;
+ env->spr[SPR_MQ] = T0 >> T1;
+ T0 = (int32_t)T0 >> T1;
+ RETURN();
+}
+
+void OPPROTO op_POWER_sreq (void)
+{
+ uint32_t tmp;
+ int32_t msk;
+
+ T1 &= 0x1FUL;
+ msk = INT32_MIN >> T1;
+ tmp = env->spr[SPR_MQ];
+ env->spr[SPR_MQ] = rotl32(T0, 32 - T1);
+ T0 = T0 >> T1;
+ T0 |= tmp & msk;
+ RETURN();
+}
+
+void OPPROTO op_POWER_srlq (void)
+{
+ uint32_t tmp;
+ int32_t msk;
+
+ msk = INT32_MIN >> (T1 & 0x1FUL);
+ if (T1 & 0x20UL)
+ msk = ~msk;
+ T1 &= 0x1FUL;
+ tmp = env->spr[SPR_MQ];
+ env->spr[SPR_MQ] = rotl32(T0, 32 - T1);
+ T0 = T0 >> T1;
+ T0 &= msk;
+ T0 |= tmp & ~msk;
+ RETURN();
+}
+
+void OPPROTO op_POWER_srq (void)
+{
+ T1 &= 0x1FUL;
+ env->spr[SPR_MQ] = rotl32(T0, 32 - T1);
+ T0 = T0 >> T1;
+ RETURN();
+}
+
+/* POWER instructions not implemented in PowerPC 601 */
+#if !defined(CONFIG_USER_ONLY)
+void OPPROTO op_POWER_mfsri (void)
+{
+ T1 = T0 >> 28;
+ T0 = env->sr[T1];
+ RETURN();
+}
+
+void OPPROTO op_POWER_rac (void)
+{
+ do_POWER_rac();
+ RETURN();
+}
+
+void OPPROTO op_POWER_rfsvc (void)
+{
+ do_POWER_rfsvc();
+ RETURN();
+}
+#endif
+
+/* PowerPC 602 specific instruction */
+#if !defined(CONFIG_USER_ONLY)
+void OPPROTO op_602_mfrom (void)
+{
+ do_op_602_mfrom();
+ RETURN();
+}
+#endif
+
+/* PowerPC 4xx specific micro-ops */
+void OPPROTO op_405_add_T0_T2 (void)
+{
+ T0 = (int32_t)T0 + (int32_t)T2;
+ RETURN();
+}
+
+void OPPROTO op_405_mulchw (void)
+{
+ T0 = ((int16_t)T0) * ((int16_t)(T1 >> 16));
+ RETURN();
+}
+
+void OPPROTO op_405_mulchwu (void)
+{
+ T0 = ((uint16_t)T0) * ((uint16_t)(T1 >> 16));
+ RETURN();
+}
+
+void OPPROTO op_405_mulhhw (void)
+{
+ T0 = ((int16_t)(T0 >> 16)) * ((int16_t)(T1 >> 16));
+ RETURN();
+}
+
+void OPPROTO op_405_mulhhwu (void)
+{
+ T0 = ((uint16_t)(T0 >> 16)) * ((uint16_t)(T1 >> 16));
+ RETURN();
+}
+
+void OPPROTO op_405_mullhw (void)
+{
+ T0 = ((int16_t)T0) * ((int16_t)T1);
+ RETURN();
+}
+
+void OPPROTO op_405_mullhwu (void)
+{
+ T0 = ((uint16_t)T0) * ((uint16_t)T1);
+ RETURN();
+}
+
+void OPPROTO op_405_check_ov (void)
+{
+ do_405_check_ov();
+ RETURN();
+}
+
+void OPPROTO op_405_check_sat (void)
+{
+ do_405_check_sat();
+ RETURN();
+}
+
+void OPPROTO op_405_check_ovu (void)
+{
+ if (likely(T0 >= T2)) {
+ xer_ov = 0;
+ } else {
+ xer_ov = 1;
+ xer_so = 1;
+ }
+ RETURN();
+}
+
+void OPPROTO op_405_check_satu (void)
+{
+ if (unlikely(T0 < T2)) {
+ /* Saturate result */
+ T0 = -1;
+ }
+ RETURN();
+}
+
+#if !defined(CONFIG_USER_ONLY)
+void OPPROTO op_load_dcr (void)
+{
+ do_load_dcr();
+ RETURN();
+}
+
+void OPPROTO op_store_dcr (void)
+{
+ do_store_dcr();
+ RETURN();
+}
+
+/* Return from critical interrupt :
+ * same as rfi, except nip & MSR are loaded from SRR2/3 instead of SRR0/1
+ */
+void OPPROTO op_40x_rfci (void)
+{
+ do_40x_rfci();
+ RETURN();
+}
+
+void OPPROTO op_rfci (void)
+{
+ do_rfci();
+ RETURN();
+}
+
+void OPPROTO op_rfdi (void)
+{
+ do_rfdi();
+ RETURN();
+}
+
+void OPPROTO op_rfmci (void)
+{
+ do_rfmci();
+ RETURN();
+}
+
+void OPPROTO op_wrte (void)
+{
+ msr_ee = T0 >> 16;
+ RETURN();
+}
+
+void OPPROTO op_4xx_tlbre_lo (void)
+{
+ do_4xx_tlbre_lo();
+ RETURN();
+}
+
+void OPPROTO op_4xx_tlbre_hi (void)
+{
+ do_4xx_tlbre_hi();
+ RETURN();
+}
+
+void OPPROTO op_4xx_tlbsx (void)
+{
+ do_4xx_tlbsx();
+ RETURN();
+}
+
+void OPPROTO op_4xx_tlbsx_ (void)
+{
+ do_4xx_tlbsx_();
+ RETURN();
+}
+
+void OPPROTO op_4xx_tlbwe_lo (void)
+{
+ do_4xx_tlbwe_lo();
+ RETURN();
+}
+
+void OPPROTO op_4xx_tlbwe_hi (void)
+{
+ do_4xx_tlbwe_hi();
+ RETURN();
+}
+#endif
+
+/* SPR micro-ops */
+/* 440 specific */
+void OPPROTO op_440_dlmzb (void)
+{
+ do_440_dlmzb();
+ RETURN();
+}
+
+void OPPROTO op_440_dlmzb_update_Rc (void)
+{
+ if (T0 == 8)
+ T0 = 0x2;
+ else if (T0 < 4)
+ T0 = 0x4;
+ else
+ T0 = 0x8;
+ RETURN();
+}
+
+#if !defined(CONFIG_USER_ONLY)
+void OPPROTO op_store_pir (void)
+{
env->spr[SPR_PIR] = T0 & 0x0000000FUL;
RETURN();
}
+
+void OPPROTO op_load_403_pb (void)
+{
+ do_load_403_pb(PARAM1);
+ RETURN();
+}
+
+void OPPROTO op_store_403_pb (void)
+{
+ do_store_403_pb(PARAM1);
+ RETURN();
+}
+
+void OPPROTO op_load_40x_pit (void)
+{
+ T0 = load_40x_pit(env);
+ RETURN();
+}
+
+void OPPROTO op_store_40x_pit (void)
+{
+ store_40x_pit(env, T0);
+ RETURN();
+}
+
+void OPPROTO op_store_40x_dbcr0 (void)
+{
+ store_40x_dbcr0(env, T0);
+}
+
+void OPPROTO op_store_40x_sler (void)
+{
+ store_40x_sler(env, T0);
+ RETURN();
+}
+
+void OPPROTO op_store_booke_tcr (void)
+{
+ store_booke_tcr(env, T0);
+ RETURN();
+}
+
+void OPPROTO op_store_booke_tsr (void)
+{
+ store_booke_tsr(env, T0);
+ RETURN();
+}
+
+#endif /* !defined(CONFIG_USER_ONLY) */
+
+#if defined(TARGET_PPCEMB)
+/* SPE extension */
+void OPPROTO op_splatw_T1_64 (void)
+{
+ T1_64 = (T1_64 << 32) | (T1_64 & 0x00000000FFFFFFFFULL);
+ RETURN();
+}
+
+void OPPROTO op_splatwi_T0_64 (void)
+{
+ uint64_t tmp = PARAM1;
+
+ T0_64 = (tmp << 32) | tmp;
+ RETURN();
+}
+
+void OPPROTO op_splatwi_T1_64 (void)
+{
+ uint64_t tmp = PARAM1;
+
+ T1_64 = (tmp << 32) | tmp;
+ RETURN();
+}
+
+void OPPROTO op_extsh_T1_64 (void)
+{
+ T1_64 = (int32_t)((int16_t)T1_64);
+ RETURN();
+}
+
+void OPPROTO op_sli16_T1_64 (void)
+{
+ T1_64 = T1_64 << 16;
+ RETURN();
+}
+
+void OPPROTO op_sli32_T1_64 (void)
+{
+ T1_64 = T1_64 << 32;
+ RETURN();
+}
+
+void OPPROTO op_srli32_T1_64 (void)
+{
+ T1_64 = T1_64 >> 32;
+ RETURN();
+}
+
+void OPPROTO op_evsel (void)
+{
+ do_evsel();
+ RETURN();
+}
+
+void OPPROTO op_evaddw (void)
+{
+ do_evaddw();
+ RETURN();
+}
+
+void OPPROTO op_evsubfw (void)
+{
+ do_evsubfw();
+ RETURN();
+}
+
+void OPPROTO op_evneg (void)
+{
+ do_evneg();
+ RETURN();
+}
+
+void OPPROTO op_evabs (void)
+{
+ do_evabs();
+ RETURN();
+}
+
+void OPPROTO op_evextsh (void)
+{
+ T0_64 = ((uint64_t)((int32_t)(int16_t)(T0_64 >> 32)) << 32) |
+ (uint64_t)((int32_t)(int16_t)T0_64);
+ RETURN();
+}
+
+void OPPROTO op_evextsb (void)
+{
+ T0_64 = ((uint64_t)((int32_t)(int8_t)(T0_64 >> 32)) << 32) |
+ (uint64_t)((int32_t)(int8_t)T0_64);
+ RETURN();
+}
+
+void OPPROTO op_evcntlzw (void)
+{
+ do_evcntlzw();
+ RETURN();
+}
+
+void OPPROTO op_evrndw (void)
+{
+ do_evrndw();
+ RETURN();
+}
+
+void OPPROTO op_brinc (void)
+{
+ do_brinc();
+ RETURN();
+}
+
+void OPPROTO op_evcntlsw (void)
+{
+ do_evcntlsw();
+ RETURN();
+}
+
+void OPPROTO op_evand (void)
+{
+ T0_64 &= T1_64;
+ RETURN();
+}
+
+void OPPROTO op_evandc (void)
+{
+ T0_64 &= ~T1_64;
+ RETURN();
+}
+
+void OPPROTO op_evor (void)
+{
+ T0_64 |= T1_64;
+ RETURN();
+}
+
+void OPPROTO op_evxor (void)
+{
+ T0_64 ^= T1_64;
+ RETURN();
+}
+
+void OPPROTO op_eveqv (void)
+{
+ T0_64 = ~(T0_64 ^ T1_64);
+ RETURN();
+}
+
+void OPPROTO op_evnor (void)
+{
+ T0_64 = ~(T0_64 | T1_64);
+ RETURN();
+}
+
+void OPPROTO op_evorc (void)
+{
+ T0_64 |= ~T1_64;
+ RETURN();
+}
+
+void OPPROTO op_evnand (void)
+{
+ T0_64 = ~(T0_64 & T1_64);
+ RETURN();
+}
+
+void OPPROTO op_evsrws (void)
+{
+ do_evsrws();
+ RETURN();
+}
+
+void OPPROTO op_evsrwu (void)
+{
+ do_evsrwu();
+ RETURN();
+}
+
+void OPPROTO op_evslw (void)
+{
+ do_evslw();
+ RETURN();
+}
+
+void OPPROTO op_evrlw (void)
+{
+ do_evrlw();
+ RETURN();
+}
+
+void OPPROTO op_evmergelo (void)
+{
+ T0_64 = (T0_64 << 32) | (T1_64 & 0x00000000FFFFFFFFULL);
+ RETURN();
+}
+
+void OPPROTO op_evmergehi (void)
+{
+ T0_64 = (T0_64 & 0xFFFFFFFF00000000ULL) | (T1_64 >> 32);
+ RETURN();
+}
+
+void OPPROTO op_evmergelohi (void)
+{
+ T0_64 = (T0_64 << 32) | (T1_64 >> 32);
+ RETURN();
+}
+
+void OPPROTO op_evmergehilo (void)
+{
+ T0_64 = (T0_64 & 0xFFFFFFFF00000000ULL) | (T1_64 & 0x00000000FFFFFFFFULL);
+ RETURN();
+}
+
+void OPPROTO op_evcmpgts (void)
+{
+ do_evcmpgts();
+ RETURN();
+}
+
+void OPPROTO op_evcmpgtu (void)
+{
+ do_evcmpgtu();
+ RETURN();
+}
+
+void OPPROTO op_evcmplts (void)
+{
+ do_evcmplts();
+ RETURN();
+}
+
+void OPPROTO op_evcmpltu (void)
+{
+ do_evcmpltu();
+ RETURN();
+}
+
+void OPPROTO op_evcmpeq (void)
+{
+ do_evcmpeq();
+ RETURN();
+}
+
+void OPPROTO op_evfssub (void)
+{
+ do_evfssub();
+ RETURN();
+}
+
+void OPPROTO op_evfsadd (void)
+{
+ do_evfsadd();
+ RETURN();
+}
+
+void OPPROTO op_evfsnabs (void)
+{
+ do_evfsnabs();
+ RETURN();
+}
+
+void OPPROTO op_evfsabs (void)
+{
+ do_evfsabs();
+ RETURN();
+}
+
+void OPPROTO op_evfsneg (void)
+{
+ do_evfsneg();
+ RETURN();
+}
+
+void OPPROTO op_evfsdiv (void)
+{
+ do_evfsdiv();
+ RETURN();
+}
+
+void OPPROTO op_evfsmul (void)
+{
+ do_evfsmul();
+ RETURN();
+}
+
+void OPPROTO op_evfscmplt (void)
+{
+ do_evfscmplt();
+ RETURN();
+}
+
+void OPPROTO op_evfscmpgt (void)
+{
+ do_evfscmpgt();
+ RETURN();
+}
+
+void OPPROTO op_evfscmpeq (void)
+{
+ do_evfscmpeq();
+ RETURN();
+}
+
+void OPPROTO op_evfscfsi (void)
+{
+ do_evfscfsi();
+ RETURN();
+}
+
+void OPPROTO op_evfscfui (void)
+{
+ do_evfscfui();
+ RETURN();
+}
+
+void OPPROTO op_evfscfsf (void)
+{
+ do_evfscfsf();
+ RETURN();
+}
+
+void OPPROTO op_evfscfuf (void)
+{
+ do_evfscfuf();
+ RETURN();
+}
+
+void OPPROTO op_evfsctsi (void)
+{
+ do_evfsctsi();
+ RETURN();
+}
+
+void OPPROTO op_evfsctui (void)
+{
+ do_evfsctui();
+ RETURN();
+}
+
+void OPPROTO op_evfsctsf (void)
+{
+ do_evfsctsf();
+ RETURN();
+}
+
+void OPPROTO op_evfsctuf (void)
+{
+ do_evfsctuf();
+ RETURN();
+}
+
+void OPPROTO op_evfsctuiz (void)
+{
+ do_evfsctuiz();
+ RETURN();
+}
+
+void OPPROTO op_evfsctsiz (void)
+{
+ do_evfsctsiz();
+ RETURN();
+}
+
+void OPPROTO op_evfststlt (void)
+{
+ do_evfststlt();
+ RETURN();
+}
+
+void OPPROTO op_evfststgt (void)
+{
+ do_evfststgt();
+ RETURN();
+}
+
+void OPPROTO op_evfststeq (void)
+{
+ do_evfststeq();
+ RETURN();
+}
+
+void OPPROTO op_efssub (void)
+{
+ T0_64 = _do_efssub(T0_64, T1_64);
+ RETURN();
+}
+
+void OPPROTO op_efsadd (void)
+{
+ T0_64 = _do_efsadd(T0_64, T1_64);
+ RETURN();
+}
+
+void OPPROTO op_efsnabs (void)
+{
+ T0_64 = _do_efsnabs(T0_64);
+ RETURN();
+}
+
+void OPPROTO op_efsabs (void)
+{
+ T0_64 = _do_efsabs(T0_64);
+ RETURN();
+}
+
+void OPPROTO op_efsneg (void)
+{
+ T0_64 = _do_efsneg(T0_64);
+ RETURN();
+}
+
+void OPPROTO op_efsdiv (void)
+{
+ T0_64 = _do_efsdiv(T0_64, T1_64);
+ RETURN();
+}
+
+void OPPROTO op_efsmul (void)
+{
+ T0_64 = _do_efsmul(T0_64, T1_64);
+ RETURN();
+}
+
+void OPPROTO op_efscmplt (void)
+{
+ do_efscmplt();
+ RETURN();
+}
+
+void OPPROTO op_efscmpgt (void)
+{
+ do_efscmpgt();
+ RETURN();
+}
+
+void OPPROTO op_efscfd (void)
+{
+ do_efscfd();
+ RETURN();
+}
+
+void OPPROTO op_efscmpeq (void)
+{
+ do_efscmpeq();
+ RETURN();
+}
+
+void OPPROTO op_efscfsi (void)
+{
+ do_efscfsi();
+ RETURN();
+}
+
+void OPPROTO op_efscfui (void)
+{
+ do_efscfui();
+ RETURN();
+}
+
+void OPPROTO op_efscfsf (void)
+{
+ do_efscfsf();
+ RETURN();
+}
+
+void OPPROTO op_efscfuf (void)
+{
+ do_efscfuf();
+ RETURN();
+}
+
+void OPPROTO op_efsctsi (void)
+{
+ do_efsctsi();
+ RETURN();
+}
+
+void OPPROTO op_efsctui (void)
+{
+ do_efsctui();
+ RETURN();
+}
+
+void OPPROTO op_efsctsf (void)
+{
+ do_efsctsf();
+ RETURN();
+}
+
+void OPPROTO op_efsctuf (void)
+{
+ do_efsctuf();
+ RETURN();
+}
+
+void OPPROTO op_efsctsiz (void)
+{
+ do_efsctsiz();
+ RETURN();
+}
+
+void OPPROTO op_efsctuiz (void)
+{
+ do_efsctuiz();
+ RETURN();
+}
+
+void OPPROTO op_efststlt (void)
+{
+ T0 = _do_efststlt(T0_64, T1_64);
+ RETURN();
+}
+
+void OPPROTO op_efststgt (void)
+{
+ T0 = _do_efststgt(T0_64, T1_64);
+ RETURN();
+}
+
+void OPPROTO op_efststeq (void)
+{
+ T0 = _do_efststeq(T0_64, T1_64);
+ RETURN();
+}
+
+void OPPROTO op_efdsub (void)
+{
+ union {
+ uint64_t u;
+ float64 f;
+ } u1, u2;
+ u1.u = T0_64;
+ u2.u = T1_64;
+ u1.f = float64_sub(u1.f, u2.f, &env->spe_status);
+ T0_64 = u1.u;
+ RETURN();
+}
+
+void OPPROTO op_efdadd (void)
+{
+ union {
+ uint64_t u;
+ float64 f;
+ } u1, u2;
+ u1.u = T0_64;
+ u2.u = T1_64;
+ u1.f = float64_add(u1.f, u2.f, &env->spe_status);
+ T0_64 = u1.u;
+ RETURN();
+}
+
+void OPPROTO op_efdcfsid (void)
+{
+ do_efdcfsi();
+ RETURN();
+}
+
+void OPPROTO op_efdcfuid (void)
+{
+ do_efdcfui();
+ RETURN();
+}
+
+void OPPROTO op_efdnabs (void)
+{
+ T0_64 |= 0x8000000000000000ULL;
+ RETURN();
+}
+
+void OPPROTO op_efdabs (void)
+{
+ T0_64 &= ~0x8000000000000000ULL;
+ RETURN();
+}
+
+void OPPROTO op_efdneg (void)
+{
+ T0_64 ^= 0x8000000000000000ULL;
+ RETURN();
+}
+
+void OPPROTO op_efddiv (void)
+{
+ union {
+ uint64_t u;
+ float64 f;
+ } u1, u2;
+ u1.u = T0_64;
+ u2.u = T1_64;
+ u1.f = float64_div(u1.f, u2.f, &env->spe_status);
+ T0_64 = u1.u;
+ RETURN();
+}
+
+void OPPROTO op_efdmul (void)
+{
+ union {
+ uint64_t u;
+ float64 f;
+ } u1, u2;
+ u1.u = T0_64;
+ u2.u = T1_64;
+ u1.f = float64_mul(u1.f, u2.f, &env->spe_status);
+ T0_64 = u1.u;
+ RETURN();
+}
+
+void OPPROTO op_efdctsidz (void)
+{
+ do_efdctsiz();
+ RETURN();
+}
+
+void OPPROTO op_efdctuidz (void)
+{
+ do_efdctuiz();
+ RETURN();
+}
+
+void OPPROTO op_efdcmplt (void)
+{
+ do_efdcmplt();
+ RETURN();
+}
+
+void OPPROTO op_efdcmpgt (void)
+{
+ do_efdcmpgt();
+ RETURN();
+}
+
+void OPPROTO op_efdcfs (void)
+{
+ do_efdcfs();
+ RETURN();
+}
+
+void OPPROTO op_efdcmpeq (void)
+{
+ do_efdcmpeq();
+ RETURN();
+}
+
+void OPPROTO op_efdcfsi (void)
+{
+ do_efdcfsi();
+ RETURN();
+}
+
+void OPPROTO op_efdcfui (void)
+{
+ do_efdcfui();
+ RETURN();
+}
+
+void OPPROTO op_efdcfsf (void)
+{
+ do_efdcfsf();
+ RETURN();
+}
+
+void OPPROTO op_efdcfuf (void)
+{
+ do_efdcfuf();
+ RETURN();
+}
+
+void OPPROTO op_efdctsi (void)
+{
+ do_efdctsi();
+ RETURN();
+}
+
+void OPPROTO op_efdctui (void)
+{
+ do_efdctui();
+ RETURN();
+}
+
+void OPPROTO op_efdctsf (void)
+{
+ do_efdctsf();
+ RETURN();
+}
+
+void OPPROTO op_efdctuf (void)
+{
+ do_efdctuf();
+ RETURN();
+}
+
+void OPPROTO op_efdctuiz (void)
+{
+ do_efdctuiz();
+ RETURN();
+}
+
+void OPPROTO op_efdctsiz (void)
+{
+ do_efdctsiz();
+ RETURN();
+}
+
+void OPPROTO op_efdtstlt (void)
+{
+ T0 = _do_efdtstlt(T0_64, T1_64);
+ RETURN();
+}
+
+void OPPROTO op_efdtstgt (void)
+{
+ T0 = _do_efdtstgt(T0_64, T1_64);
+ RETURN();
+}
+
+void OPPROTO op_efdtsteq (void)
+{
+ T0 = _do_efdtsteq(T0_64, T1_64);
+ RETURN();
+}
+#endif /* defined(TARGET_PPCEMB) */
Modified: trunk/src/host/qemu-neo1973/target-ppc/op_helper.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-ppc/op_helper.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/target-ppc/op_helper.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -1,7 +1,7 @@
/*
* PowerPC emulation helpers for qemu.
*
- * Copyright (c) 2003-2005 Jocelyn Mayer
+ * Copyright (c) 2003-2007 Jocelyn Mayer
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -19,26 +19,28 @@
*/
#include "exec.h"
+#include "op_helper.h"
+
#define MEMSUFFIX _raw
+#include "op_helper.h"
#include "op_helper_mem.h"
#if !defined(CONFIG_USER_ONLY)
#define MEMSUFFIX _user
+#include "op_helper.h"
#include "op_helper_mem.h"
#define MEMSUFFIX _kernel
+#include "op_helper.h"
#include "op_helper_mem.h"
#endif
//#define DEBUG_OP
//#define DEBUG_EXCEPTIONS
+//#define DEBUG_SOFTWARE_TLB
//#define FLUSH_ALL_TLBS
-#define Ts0 (long)((target_long)T0)
-#define Ts1 (long)((target_long)T1)
-#define Ts2 (long)((target_long)T2)
-
/*****************************************************************************/
/* Exceptions processing helpers */
-void cpu_loop_exit(void)
+void cpu_loop_exit (void)
{
longjmp(env->jmp_env, 1);
}
@@ -50,86 +52,266 @@
#endif
switch (exception) {
case EXCP_PROGRAM:
- if (error_code == EXCP_FP && msr_fe0 == 0 && msr_fe1 == 0)
- return;
- break;
+ if (error_code == EXCP_FP && msr_fe0 == 0 && msr_fe1 == 0)
+ return;
+ break;
default:
- break;
-}
+ break;
+ }
env->exception_index = exception;
env->error_code = error_code;
- cpu_loop_exit();
- }
+ cpu_loop_exit();
+}
void do_raise_exception (uint32_t exception)
{
do_raise_exception_err(exception, 0);
}
+void cpu_dump_EA (target_ulong EA);
+void do_print_mem_EA (target_ulong EA)
+{
+ cpu_dump_EA(EA);
+}
+
/*****************************************************************************/
-/* Fixed point operations helpers */
-void do_addo (void)
+/* Registers load and stores */
+void do_load_cr (void)
{
- T2 = T0;
- T0 += T1;
- if (likely(!((T2 ^ T1 ^ (-1)) & (T2 ^ T0) & (1 << 31)))) {
- xer_ov = 0;
- } else {
- xer_so = 1;
- xer_ov = 1;
+ T0 = (env->crf[0] << 28) |
+ (env->crf[1] << 24) |
+ (env->crf[2] << 20) |
+ (env->crf[3] << 16) |
+ (env->crf[4] << 12) |
+ (env->crf[5] << 8) |
+ (env->crf[6] << 4) |
+ (env->crf[7] << 0);
+}
+
+void do_store_cr (uint32_t mask)
+{
+ int i, sh;
+
+ for (i = 0, sh = 7; i < 8; i++, sh --) {
+ if (mask & (1 << sh))
+ env->crf[i] = (T0 >> (sh * 4)) & 0xFUL;
}
}
-void do_addco (void)
+void do_load_xer (void)
{
- T2 = T0;
- T0 += T1;
- if (likely(T0 >= T2)) {
- xer_ca = 0;
- } else {
- xer_ca = 1;
+ T0 = (xer_so << XER_SO) |
+ (xer_ov << XER_OV) |
+ (xer_ca << XER_CA) |
+ (xer_bc << XER_BC) |
+ (xer_cmp << XER_CMP);
+}
+
+void do_store_xer (void)
+{
+ xer_so = (T0 >> XER_SO) & 0x01;
+ xer_ov = (T0 >> XER_OV) & 0x01;
+ xer_ca = (T0 >> XER_CA) & 0x01;
+ xer_cmp = (T0 >> XER_CMP) & 0xFF;
+ xer_bc = (T0 >> XER_BC) & 0x7F;
+}
+
+void do_load_fpscr (void)
+{
+ /* The 32 MSB of the target fpr are undefined.
+ * They'll be zero...
+ */
+ union {
+ float64 d;
+ struct {
+ uint32_t u[2];
+ } s;
+ } u;
+ int i;
+
+#if defined(WORDS_BIGENDIAN)
+#define WORD0 0
+#define WORD1 1
+#else
+#define WORD0 1
+#define WORD1 0
+#endif
+ u.s.u[WORD0] = 0;
+ u.s.u[WORD1] = 0;
+ for (i = 0; i < 8; i++)
+ u.s.u[WORD1] |= env->fpscr[i] << (4 * i);
+ FT0 = u.d;
+}
+
+void do_store_fpscr (uint32_t mask)
+{
+ /*
+ * We use only the 32 LSB of the incoming fpr
+ */
+ union {
+ double d;
+ struct {
+ uint32_t u[2];
+ } s;
+ } u;
+ int i, rnd_type;
+
+ u.d = FT0;
+ if (mask & 0x80)
+ env->fpscr[0] = (env->fpscr[0] & 0x9) | ((u.s.u[WORD1] >> 28) & ~0x9);
+ for (i = 1; i < 7; i++) {
+ if (mask & (1 << (7 - i)))
+ env->fpscr[i] = (u.s.u[WORD1] >> (4 * (7 - i))) & 0xF;
}
- if (likely(!((T2 ^ T1 ^ (-1)) & (T2 ^ T0) & (1 << 31)))) {
- xer_ov = 0;
- } else {
- xer_so = 1;
- xer_ov = 1;
+ /* TODO: update FEX & VX */
+ /* Set rounding mode */
+ switch (env->fpscr[0] & 0x3) {
+ case 0:
+ /* Best approximation (round to nearest) */
+ rnd_type = float_round_nearest_even;
+ break;
+ case 1:
+ /* Smaller magnitude (round toward zero) */
+ rnd_type = float_round_to_zero;
+ break;
+ case 2:
+ /* Round toward +infinite */
+ rnd_type = float_round_up;
+ break;
+ default:
+ case 3:
+ /* Round toward -infinite */
+ rnd_type = float_round_down;
+ break;
}
+ set_float_rounding_mode(rnd_type, &env->fp_status);
}
+target_ulong ppc_load_dump_spr (int sprn)
+{
+ if (loglevel != 0) {
+ fprintf(logfile, "Read SPR %d %03x => " ADDRX "\n",
+ sprn, sprn, env->spr[sprn]);
+ }
+
+ return env->spr[sprn];
+}
+
+void ppc_store_dump_spr (int sprn, target_ulong val)
+{
+ if (loglevel != 0) {
+ fprintf(logfile, "Write SPR %d %03x => " ADDRX " <= " ADDRX "\n",
+ sprn, sprn, env->spr[sprn], val);
+ }
+ env->spr[sprn] = val;
+}
+
+/*****************************************************************************/
+/* Fixed point operations helpers */
+#if defined(TARGET_PPC64)
+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;
+#if defined(DEBUG_MULDIV)
+ printf("mul: 0x%016llx * 0x%016llx = 0x%016llx%016llx\n",
+ a, b, *phigh, *plow);
+#endif
+}
+
+void do_mul64 (uint64_t *plow, uint64_t *phigh)
+{
+ mul64(plow, phigh, T0, T1);
+}
+
+static void imul64 (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);
+ }
+}
+
+void do_imul64 (uint64_t *plow, uint64_t *phigh)
+{
+ imul64(plow, phigh, T0, T1);
+}
+#endif
+
void do_adde (void)
{
T2 = T0;
T0 += T1 + xer_ca;
- if (likely(!(T0 < T2 || (xer_ca == 1 && T0 == T2)))) {
+ if (likely(!((uint32_t)T0 < (uint32_t)T2 ||
+ (xer_ca == 1 && (uint32_t)T0 == (uint32_t)T2)))) {
xer_ca = 0;
} else {
xer_ca = 1;
}
}
-void do_addeo (void)
+#if defined(TARGET_PPC64)
+void do_adde_64 (void)
{
T2 = T0;
T0 += T1 + xer_ca;
- if (likely(!(T0 < T2 || (xer_ca == 1 && T0 == T2)))) {
+ if (likely(!((uint64_t)T0 < (uint64_t)T2 ||
+ (xer_ca == 1 && (uint64_t)T0 == (uint64_t)T2)))) {
xer_ca = 0;
} else {
xer_ca = 1;
}
- if (likely(!((T2 ^ T1 ^ (-1)) & (T2 ^ T0) & (1 << 31)))) {
- xer_ov = 0;
- } else {
- xer_so = 1;
- xer_ov = 1;
- }
}
+#endif
void do_addmeo (void)
{
T1 = T0;
T0 += xer_ca + (-1);
- if (likely(!(T1 & (T1 ^ T0) & (1 << 31)))) {
+ if (likely(!((uint32_t)T1 &
+ ((uint32_t)T1 ^ (uint32_t)T0) & (1UL << 31)))) {
xer_ov = 0;
} else {
xer_so = 1;
@@ -139,28 +321,29 @@
xer_ca = 1;
}
-void do_addzeo (void)
+#if defined(TARGET_PPC64)
+void do_addmeo_64 (void)
{
T1 = T0;
- T0 += xer_ca;
- if (likely(!((T1 ^ (-1)) & (T1 ^ T0) & (1 << 31)))) {
+ T0 += xer_ca + (-1);
+ if (likely(!((uint64_t)T1 &
+ ((uint64_t)T1 ^ (uint64_t)T0) & (1ULL << 63)))) {
xer_ov = 0;
} else {
xer_so = 1;
xer_ov = 1;
}
- if (likely(T0 >= T1)) {
- xer_ca = 0;
- } else {
+ if (likely(T1 != 0))
xer_ca = 1;
- }
}
+#endif
void do_divwo (void)
{
- if (likely(!((Ts0 == INT32_MIN && Ts1 == -1) || Ts1 == 0))) {
+ if (likely(!(((int32_t)T0 == INT32_MIN && (int32_t)T1 == -1) ||
+ (int32_t)T1 == 0))) {
xer_ov = 0;
- T0 = (Ts0 / Ts1);
+ T0 = (int32_t)T0 / (int32_t)T1;
} else {
xer_so = 1;
xer_ov = 1;
@@ -168,6 +351,21 @@
}
}
+#if defined(TARGET_PPC64)
+void do_divdo (void)
+{
+ if (likely(!(((int64_t)T0 == INT64_MIN && (int64_t)T1 == -1ULL) ||
+ (int64_t)T1 == 0))) {
+ xer_ov = 0;
+ T0 = (int64_t)T0 / (int64_t)T1;
+ } else {
+ xer_so = 1;
+ xer_ov = 1;
+ T0 = (-1ULL) * ((uint64_t)T0 >> 63);
+ }
+}
+#endif
+
void do_divwuo (void)
{
if (likely((uint32_t)T1 != 0)) {
@@ -180,9 +378,23 @@
}
}
+#if defined(TARGET_PPC64)
+void do_divduo (void)
+{
+ if (likely((uint64_t)T1 != 0)) {
+ xer_ov = 0;
+ T0 = (uint64_t)T0 / (uint64_t)T1;
+ } else {
+ xer_so = 1;
+ xer_ov = 1;
+ T0 = 0;
+ }
+}
+#endif
+
void do_mullwo (void)
{
- int64_t res = (int64_t)Ts0 * (int64_t)Ts1;
+ int64_t res = (int64_t)T0 * (int64_t)T1;
if (likely((int32_t)res == res)) {
xer_ov = 0;
@@ -193,133 +405,232 @@
T0 = (int32_t)res;
}
-void do_nego (void)
+#if defined(TARGET_PPC64)
+void do_mulldo (void)
{
- if (likely(T0 != INT32_MIN)) {
+ int64_t th;
+ uint64_t tl;
+
+ do_imul64(&tl, &th);
+ if (likely(th == 0)) {
xer_ov = 0;
- T0 = -Ts0;
} else {
xer_ov = 1;
xer_so = 1;
}
+ T0 = (int64_t)tl;
}
+#endif
-void do_subfo (void)
+void do_nego (void)
{
- T2 = T0;
- T0 = T1 - T0;
- if (likely(!(((~T2) ^ T1 ^ (-1)) & ((~T2) ^ T0) & (1 << 31)))) {
+ if (likely((int32_t)T0 != INT32_MIN)) {
xer_ov = 0;
+ T0 = -(int32_t)T0;
} else {
+ xer_ov = 1;
xer_so = 1;
- xer_ov = 1;
}
- RETURN();
}
-void do_subfco (void)
+#if defined(TARGET_PPC64)
+void do_nego_64 (void)
{
- T2 = T0;
- T0 = T1 - T0;
- if (likely(T0 > T1)) {
- xer_ca = 0;
- } else {
- xer_ca = 1;
- }
- if (likely(!(((~T2) ^ T1 ^ (-1)) & ((~T2) ^ T0) & (1 << 31)))) {
+ if (likely((int64_t)T0 != INT64_MIN)) {
xer_ov = 0;
+ T0 = -(int64_t)T0;
} else {
+ xer_ov = 1;
xer_so = 1;
- xer_ov = 1;
}
}
+#endif
void do_subfe (void)
{
T0 = T1 + ~T0 + xer_ca;
- if (likely(T0 >= T1 && (xer_ca == 0 || T0 != T1))) {
+ if (likely((uint32_t)T0 >= (uint32_t)T1 &&
+ (xer_ca == 0 || (uint32_t)T0 != (uint32_t)T1))) {
xer_ca = 0;
} else {
xer_ca = 1;
}
}
-void do_subfeo (void)
+#if defined(TARGET_PPC64)
+void do_subfe_64 (void)
{
- T2 = T0;
T0 = T1 + ~T0 + xer_ca;
- if (likely(!((~T2 ^ T1 ^ (-1)) & (~T2 ^ T0) & (1 << 31)))) {
+ if (likely((uint64_t)T0 >= (uint64_t)T1 &&
+ (xer_ca == 0 || (uint64_t)T0 != (uint64_t)T1))) {
+ xer_ca = 0;
+ } else {
+ xer_ca = 1;
+ }
+}
+#endif
+
+void do_subfmeo (void)
+{
+ T1 = T0;
+ T0 = ~T0 + xer_ca - 1;
+ if (likely(!((uint32_t)~T1 & ((uint32_t)~T1 ^ (uint32_t)T0) &
+ (1UL << 31)))) {
xer_ov = 0;
} else {
xer_so = 1;
xer_ov = 1;
}
- if (likely(T0 >= T1 && (xer_ca == 0 || T0 != T1))) {
- xer_ca = 0;
- } else {
+ if (likely((uint32_t)T1 != UINT32_MAX))
xer_ca = 1;
- }
}
-void do_subfmeo (void)
+#if defined(TARGET_PPC64)
+void do_subfmeo_64 (void)
{
T1 = T0;
T0 = ~T0 + xer_ca - 1;
- if (likely(!(~T1 & (~T1 ^ T0) & (1 << 31)))) {
+ if (likely(!((uint64_t)~T1 & ((uint64_t)~T1 ^ (uint64_t)T0) &
+ (1ULL << 63)))) {
xer_ov = 0;
} else {
xer_so = 1;
xer_ov = 1;
}
- if (likely(T1 != -1))
+ if (likely((uint64_t)T1 != UINT64_MAX))
xer_ca = 1;
}
+#endif
void do_subfzeo (void)
{
T1 = T0;
T0 = ~T0 + xer_ca;
- if (likely(!((~T1 ^ (-1)) & ((~T1) ^ T0) & (1 << 31)))) {
+ if (likely(!(((uint32_t)~T1 ^ UINT32_MAX) &
+ ((uint32_t)(~T1) ^ (uint32_t)T0) & (1UL << 31)))) {
xer_ov = 0;
} else {
xer_ov = 1;
xer_so = 1;
}
- if (likely(T0 >= ~T1)) {
+ if (likely((uint32_t)T0 >= (uint32_t)~T1)) {
xer_ca = 0;
} else {
xer_ca = 1;
}
}
+#if defined(TARGET_PPC64)
+void do_subfzeo_64 (void)
+{
+ T1 = T0;
+ T0 = ~T0 + xer_ca;
+ if (likely(!(((uint64_t)~T1 ^ UINT64_MAX) &
+ ((uint64_t)(~T1) ^ (uint64_t)T0) & (1ULL << 63)))) {
+ xer_ov = 0;
+ } else {
+ xer_ov = 1;
+ xer_so = 1;
+ }
+ if (likely((uint64_t)T0 >= (uint64_t)~T1)) {
+ xer_ca = 0;
+ } else {
+ xer_ca = 1;
+ }
+}
+#endif
+
/* shift right arithmetic helper */
void do_sraw (void)
{
int32_t ret;
if (likely(!(T1 & 0x20UL))) {
- if (likely(T1 != 0)) {
+ if (likely((uint32_t)T1 != 0)) {
ret = (int32_t)T0 >> (T1 & 0x1fUL);
if (likely(ret >= 0 || ((int32_t)T0 & ((1 << T1) - 1)) == 0)) {
- xer_ca = 0;
+ xer_ca = 0;
} else {
- xer_ca = 1;
+ xer_ca = 1;
}
} else {
- ret = T0;
+ ret = T0;
xer_ca = 0;
}
} else {
ret = (-1) * ((uint32_t)T0 >> 31);
if (likely(ret >= 0 || ((uint32_t)T0 & ~0x80000000UL) == 0)) {
xer_ca = 0;
+ } else {
+ xer_ca = 1;
+ }
+ }
+ T0 = ret;
+}
+
+#if defined(TARGET_PPC64)
+void do_srad (void)
+{
+ int64_t ret;
+
+ if (likely(!(T1 & 0x40UL))) {
+ if (likely((uint64_t)T1 != 0)) {
+ ret = (int64_t)T0 >> (T1 & 0x3FUL);
+ if (likely(ret >= 0 || ((int64_t)T0 & ((1 << T1) - 1)) == 0)) {
+ xer_ca = 0;
+ } else {
+ xer_ca = 1;
+ }
+ } else {
+ ret = T0;
+ xer_ca = 0;
+ }
} else {
+ ret = (-1) * ((uint64_t)T0 >> 63);
+ if (likely(ret >= 0 || ((uint64_t)T0 & ~0x8000000000000000ULL) == 0)) {
+ xer_ca = 0;
+ } else {
xer_ca = 1;
+ }
}
- }
T0 = ret;
}
+#endif
+static inline int popcnt (uint32_t val)
+{
+ int i;
+
+ for (i = 0; val != 0;)
+ val = val ^ (val - 1);
+
+ return i;
+}
+
+void do_popcntb (void)
+{
+ uint32_t ret;
+ int i;
+
+ ret = 0;
+ for (i = 0; i < 32; i += 8)
+ ret |= popcnt((T0 >> i) & 0xFF) << i;
+ T0 = ret;
+}
+
+#if defined(TARGET_PPC64)
+void do_popcntb_64 (void)
+{
+ uint64_t ret;
+ int i;
+
+ ret = 0;
+ for (i = 0; i < 64; i += 8)
+ ret |= popcnt((T0 >> i) & 0xFF) << i;
+ T0 = ret;
+}
+#endif
+
/*****************************************************************************/
/* Floating point operations helpers */
void do_fctiw (void)
@@ -329,11 +640,13 @@
uint64_t i;
} p;
+ p.i = float64_to_int32(FT0, &env->fp_status);
+#if USE_PRECISE_EMULATION
/* XXX: higher bits are not supposed to be significant.
- * to make tests easier, return the same as a real PowerPC 750 (aka G3)
+ * to make tests easier, return the same as a real PowerPC 750 (aka G3)
*/
- p.i = float64_to_int32(FT0, &env->fp_status);
p.i |= 0xFFF80000ULL << 32;
+#endif
FT0 = p.d;
}
@@ -344,26 +657,132 @@
uint64_t i;
} p;
+ p.i = float64_to_int32_round_to_zero(FT0, &env->fp_status);
+#if USE_PRECISE_EMULATION
/* XXX: higher bits are not supposed to be significant.
- * to make tests easier, return the same as a real PowerPC 750 (aka G3)
+ * to make tests easier, return the same as a real PowerPC 750 (aka G3)
*/
- p.i = float64_to_int32_round_to_zero(FT0, &env->fp_status);
p.i |= 0xFFF80000ULL << 32;
+#endif
FT0 = p.d;
}
+#if defined(TARGET_PPC64)
+void do_fcfid (void)
+{
+ union {
+ double d;
+ uint64_t i;
+ } p;
+
+ p.d = FT0;
+ FT0 = int64_to_float64(p.i, &env->fp_status);
+}
+
+void do_fctid (void)
+{
+ union {
+ double d;
+ uint64_t i;
+ } p;
+
+ p.i = float64_to_int64(FT0, &env->fp_status);
+ FT0 = p.d;
+}
+
+void do_fctidz (void)
+{
+ union {
+ double d;
+ uint64_t i;
+ } p;
+
+ p.i = float64_to_int64_round_to_zero(FT0, &env->fp_status);
+ FT0 = p.d;
+}
+
+#endif
+
+#if USE_PRECISE_EMULATION
+void do_fmadd (void)
+{
+#ifdef FLOAT128
+ float128 ft0_128, ft1_128;
+
+ ft0_128 = float64_to_float128(FT0, &env->fp_status);
+ ft1_128 = float64_to_float128(FT1, &env->fp_status);
+ ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
+ ft1_128 = float64_to_float128(FT2, &env->fp_status);
+ ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
+ FT0 = float128_to_float64(ft0_128, &env->fp_status);
+#else
+ /* This is OK on x86 hosts */
+ FT0 = (FT0 * FT1) + FT2;
+#endif
+}
+
+void do_fmsub (void)
+{
+#ifdef FLOAT128
+ float128 ft0_128, ft1_128;
+
+ ft0_128 = float64_to_float128(FT0, &env->fp_status);
+ ft1_128 = float64_to_float128(FT1, &env->fp_status);
+ ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
+ ft1_128 = float64_to_float128(FT2, &env->fp_status);
+ ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
+ FT0 = float128_to_float64(ft0_128, &env->fp_status);
+#else
+ /* This is OK on x86 hosts */
+ FT0 = (FT0 * FT1) - FT2;
+#endif
+}
+#endif /* USE_PRECISE_EMULATION */
+
void do_fnmadd (void)
{
+#if USE_PRECISE_EMULATION
+#ifdef FLOAT128
+ float128 ft0_128, ft1_128;
+
+ ft0_128 = float64_to_float128(FT0, &env->fp_status);
+ ft1_128 = float64_to_float128(FT1, &env->fp_status);
+ ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
+ ft1_128 = float64_to_float128(FT2, &env->fp_status);
+ ft0_128 = float128_add(ft0_128, ft1_128, &env->fp_status);
+ FT0 = float128_to_float64(ft0_128, &env->fp_status);
+#else
+ /* This is OK on x86 hosts */
+ FT0 = (FT0 * FT1) + FT2;
+#endif
+#else
FT0 = float64_mul(FT0, FT1, &env->fp_status);
FT0 = float64_add(FT0, FT2, &env->fp_status);
+#endif
if (likely(!isnan(FT0)))
FT0 = float64_chs(FT0);
}
void do_fnmsub (void)
{
+#if USE_PRECISE_EMULATION
+#ifdef FLOAT128
+ float128 ft0_128, ft1_128;
+
+ ft0_128 = float64_to_float128(FT0, &env->fp_status);
+ ft1_128 = float64_to_float128(FT1, &env->fp_status);
+ ft0_128 = float128_mul(ft0_128, ft1_128, &env->fp_status);
+ ft1_128 = float64_to_float128(FT2, &env->fp_status);
+ ft0_128 = float128_sub(ft0_128, ft1_128, &env->fp_status);
+ FT0 = float128_to_float64(ft0_128, &env->fp_status);
+#else
+ /* This is OK on x86 hosts */
+ FT0 = (FT0 * FT1) - FT2;
+#endif
+#else
FT0 = float64_mul(FT0, FT1, &env->fp_status);
FT0 = float64_sub(FT0, FT2, &env->fp_status);
+#endif
if (likely(!isnan(FT0)))
FT0 = float64_chs(FT0);
}
@@ -381,7 +800,12 @@
} p;
if (likely(isnormal(FT0))) {
- FT0 = (float)(1.0 / FT0);
+#if USE_PRECISE_EMULATION
+ FT0 = float64_div(1.0, FT0, &env->fp_status);
+ FT0 = float64_to_float32(FT0, &env->fp_status);
+#else
+ FT0 = float32_div(1.0, FT0, &env->fp_status);
+#endif
} else {
p.d = FT0;
if (p.i == 0x8000000000000000ULL) {
@@ -467,8 +891,8 @@
} else {
T0 = 0x01UL;
env->fpscr[4] |= 0x1;
- /* I don't know how to test "quiet" nan... */
- if (0 /* || ! quiet_nan(...) */) {
+ if (!float64_is_signaling_nan(FT0) || !float64_is_signaling_nan(FT1)) {
+ /* Quiet NaN case */
env->fpscr[6] |= 0x1;
if (!(env->fpscr[1] & 0x8))
env->fpscr[4] |= 0x8;
@@ -479,63 +903,1307 @@
env->fpscr[3] = T0;
}
+#if !defined (CONFIG_USER_ONLY)
+void cpu_dump_rfi (target_ulong RA, target_ulong msr);
void do_rfi (void)
{
- env->nip = env->spr[SPR_SRR0] & ~0x00000003;
- T0 = env->spr[SPR_SRR1] & ~0xFFFF0000UL;
- do_store_msr(env, T0);
+#if defined(TARGET_PPC64)
+ if (env->spr[SPR_SRR1] & (1ULL << MSR_SF)) {
+ env->nip = (uint64_t)(env->spr[SPR_SRR0] & ~0x00000003);
+ do_store_msr(env, (uint64_t)(env->spr[SPR_SRR1] & ~0xFFFF0000UL));
+ } else {
+ env->nip = (uint32_t)(env->spr[SPR_SRR0] & ~0x00000003);
+ ppc_store_msr_32(env, (uint32_t)(env->spr[SPR_SRR1] & ~0xFFFF0000UL));
+ }
+#else
+ env->nip = (uint32_t)(env->spr[SPR_SRR0] & ~0x00000003);
+ do_store_msr(env, (uint32_t)(env->spr[SPR_SRR1] & ~0xFFFF0000UL));
+#endif
#if defined (DEBUG_OP)
- dump_rfi();
+ cpu_dump_rfi(env->nip, do_load_msr(env));
#endif
env->interrupt_request |= CPU_INTERRUPT_EXITTB;
}
-void do_tw (uint32_t cmp, int flags)
+#if defined(TARGET_PPC64)
+void do_rfid (void)
{
- if (!likely(!((Ts0 < (int32_t)cmp && (flags & 0x10)) ||
- (Ts0 > (int32_t)cmp && (flags & 0x08)) ||
- (Ts0 == (int32_t)cmp && (flags & 0x04)) ||
- (T0 < cmp && (flags & 0x02)) ||
- (T0 > cmp && (flags & 0x01)))))
+ if (env->spr[SPR_SRR1] & (1ULL << MSR_SF)) {
+ env->nip = (uint64_t)(env->spr[SPR_SRR0] & ~0x00000003);
+ do_store_msr(env, (uint64_t)(env->spr[SPR_SRR1] & ~0xFFFF0000UL));
+ } else {
+ env->nip = (uint32_t)(env->spr[SPR_SRR0] & ~0x00000003);
+ do_store_msr(env, (uint32_t)(env->spr[SPR_SRR1] & ~0xFFFF0000UL));
+ }
+#if defined (DEBUG_OP)
+ cpu_dump_rfi(env->nip, do_load_msr(env));
+#endif
+ env->interrupt_request |= CPU_INTERRUPT_EXITTB;
+}
+#endif
+#endif
+
+void do_tw (int flags)
+{
+ if (!likely(!(((int32_t)T0 < (int32_t)T1 && (flags & 0x10)) ||
+ ((int32_t)T0 > (int32_t)T1 && (flags & 0x08)) ||
+ ((int32_t)T0 == (int32_t)T1 && (flags & 0x04)) ||
+ ((uint32_t)T0 < (uint32_t)T1 && (flags & 0x02)) ||
+ ((uint32_t)T0 > (uint32_t)T1 && (flags & 0x01))))) {
do_raise_exception_err(EXCP_PROGRAM, EXCP_TRAP);
+ }
}
-/* Instruction cache invalidation helper */
-void do_icbi (void)
+#if defined(TARGET_PPC64)
+void do_td (int flags)
{
- uint32_t tmp;
- /* Invalidate one cache line :
- * PowerPC specification says this is to be treated like a load
- * (not a fetch) by the MMU. To be sure it will be so,
- * do the load "by hand".
+ if (!likely(!(((int64_t)T0 < (int64_t)T1 && (flags & 0x10)) ||
+ ((int64_t)T0 > (int64_t)T1 && (flags & 0x08)) ||
+ ((int64_t)T0 == (int64_t)T1 && (flags & 0x04)) ||
+ ((uint64_t)T0 < (uint64_t)T1 && (flags & 0x02)) ||
+ ((uint64_t)T0 > (uint64_t)T1 && (flags & 0x01)))))
+ do_raise_exception_err(EXCP_PROGRAM, EXCP_TRAP);
+}
+#endif
+
+/*****************************************************************************/
+/* PowerPC 601 specific instructions (POWER bridge) */
+void do_POWER_abso (void)
+{
+ if ((uint32_t)T0 == INT32_MIN) {
+ T0 = INT32_MAX;
+ xer_ov = 1;
+ xer_so = 1;
+ } else {
+ T0 = -T0;
+ xer_ov = 0;
+ }
+}
+
+void do_POWER_clcs (void)
+{
+ switch (T0) {
+ case 0x0CUL:
+ /* Instruction cache line size */
+ T0 = ICACHE_LINE_SIZE;
+ break;
+ case 0x0DUL:
+ /* Data cache line size */
+ T0 = DCACHE_LINE_SIZE;
+ break;
+ case 0x0EUL:
+ /* Minimum cache line size */
+ T0 = ICACHE_LINE_SIZE < DCACHE_LINE_SIZE ?
+ ICACHE_LINE_SIZE : DCACHE_LINE_SIZE;
+ break;
+ case 0x0FUL:
+ /* Maximum cache line size */
+ T0 = ICACHE_LINE_SIZE > DCACHE_LINE_SIZE ?
+ ICACHE_LINE_SIZE : DCACHE_LINE_SIZE;
+ break;
+ default:
+ /* Undefined */
+ break;
+ }
+}
+
+void do_POWER_div (void)
+{
+ uint64_t tmp;
+
+ if (((int32_t)T0 == INT32_MIN && (int32_t)T1 == -1) || (int32_t)T1 == 0) {
+ T0 = (long)((-1) * (T0 >> 31));
+ env->spr[SPR_MQ] = 0;
+ } else {
+ tmp = ((uint64_t)T0 << 32) | env->spr[SPR_MQ];
+ env->spr[SPR_MQ] = tmp % T1;
+ T0 = tmp / (int32_t)T1;
+ }
+}
+
+void do_POWER_divo (void)
+{
+ int64_t tmp;
+
+ if (((int32_t)T0 == INT32_MIN && (int32_t)T1 == -1) || (int32_t)T1 == 0) {
+ T0 = (long)((-1) * (T0 >> 31));
+ env->spr[SPR_MQ] = 0;
+ xer_ov = 1;
+ xer_so = 1;
+ } else {
+ tmp = ((uint64_t)T0 << 32) | env->spr[SPR_MQ];
+ env->spr[SPR_MQ] = tmp % T1;
+ tmp /= (int32_t)T1;
+ if (tmp > (int64_t)INT32_MAX || tmp < (int64_t)INT32_MIN) {
+ xer_ov = 1;
+ xer_so = 1;
+ } else {
+ xer_ov = 0;
+ }
+ T0 = tmp;
+ }
+}
+
+void do_POWER_divs (void)
+{
+ if (((int32_t)T0 == INT32_MIN && (int32_t)T1 == -1) || (int32_t)T1 == 0) {
+ T0 = (long)((-1) * (T0 >> 31));
+ env->spr[SPR_MQ] = 0;
+ } else {
+ env->spr[SPR_MQ] = T0 % T1;
+ T0 = (int32_t)T0 / (int32_t)T1;
+ }
+}
+
+void do_POWER_divso (void)
+{
+ if (((int32_t)T0 == INT32_MIN && (int32_t)T1 == -1) || (int32_t)T1 == 0) {
+ T0 = (long)((-1) * (T0 >> 31));
+ env->spr[SPR_MQ] = 0;
+ xer_ov = 1;
+ xer_so = 1;
+ } else {
+ T0 = (int32_t)T0 / (int32_t)T1;
+ env->spr[SPR_MQ] = (int32_t)T0 % (int32_t)T1;
+ xer_ov = 0;
+ }
+}
+
+void do_POWER_dozo (void)
+{
+ if ((int32_t)T1 > (int32_t)T0) {
+ T2 = T0;
+ T0 = T1 - T0;
+ if (((uint32_t)(~T2) ^ (uint32_t)T1 ^ UINT32_MAX) &
+ ((uint32_t)(~T2) ^ (uint32_t)T0) & (1UL << 31)) {
+ xer_so = 1;
+ xer_ov = 1;
+ } else {
+ xer_ov = 0;
+ }
+ } else {
+ T0 = 0;
+ xer_ov = 0;
+ }
+}
+
+void do_POWER_maskg (void)
+{
+ uint32_t ret;
+
+ if ((uint32_t)T0 == (uint32_t)(T1 + 1)) {
+ ret = -1;
+ } else {
+ ret = (((uint32_t)(-1)) >> ((uint32_t)T0)) ^
+ (((uint32_t)(-1) >> ((uint32_t)T1)) >> 1);
+ if ((uint32_t)T0 > (uint32_t)T1)
+ ret = ~ret;
+ }
+ T0 = ret;
+}
+
+void do_POWER_mulo (void)
+{
+ uint64_t tmp;
+
+ tmp = (uint64_t)T0 * (uint64_t)T1;
+ env->spr[SPR_MQ] = tmp >> 32;
+ T0 = tmp;
+ if (tmp >> 32 != ((uint64_t)T0 >> 16) * ((uint64_t)T1 >> 16)) {
+ xer_ov = 1;
+ xer_so = 1;
+ } else {
+ xer_ov = 0;
+ }
+}
+
+#if !defined (CONFIG_USER_ONLY)
+void do_POWER_rac (void)
+{
+#if 0
+ mmu_ctx_t ctx;
+
+ /* We don't have to generate many instances of this instruction,
+ * as rac is supervisor only.
*/
-#if defined(TARGET_PPC64)
- if (!msr_sf)
- T0 &= 0xFFFFFFFFULL;
+ if (get_physical_address(env, &ctx, T0, 0, ACCESS_INT, 1) == 0)
+ T0 = ctx.raddr;
#endif
- tmp = ldl_kernel(T0);
- T0 &= ~(ICACHE_LINE_SIZE - 1);
- tb_invalidate_page_range(T0, T0 + ICACHE_LINE_SIZE);
}
-/*****************************************************************************/
-/* MMU related helpers */
-/* TLB invalidation helpers */
-void do_tlbia (void)
+void do_POWER_rfsvc (void)
{
- tlb_flush(env, 1);
+ env->nip = env->lr & ~0x00000003UL;
+ T0 = env->ctr & 0x0000FFFFUL;
+ do_store_msr(env, T0);
+#if defined (DEBUG_OP)
+ cpu_dump_rfi(env->nip, do_load_msr(env));
+#endif
+ env->interrupt_request |= CPU_INTERRUPT_EXITTB;
}
-void do_tlbie (void)
+/* PowerPC 601 BAT management helper */
+void do_store_601_batu (int nr)
{
-#if !defined(FLUSH_ALL_TLBS)
- tlb_flush_page(env, T0);
+ do_store_ibatu(env, nr, (uint32_t)T0);
+ env->DBAT[0][nr] = env->IBAT[0][nr];
+ env->DBAT[1][nr] = env->IBAT[1][nr];
+}
+#endif
+
+/*****************************************************************************/
+/* 602 specific instructions */
+/* mfrom is the most crazy instruction ever seen, imho ! */
+/* Real implementation uses a ROM table. Do the same */
+#define USE_MFROM_ROM_TABLE
+void do_op_602_mfrom (void)
+{
+ if (likely(T0 < 602)) {
+#if defined(USE_MFROM_ROM_TABLE)
+#include "mfrom_table.c"
+ T0 = mfrom_ROM_table[T0];
#else
- do_tlbia();
+ double d;
+ /* Extremly decomposed:
+ * -T0 / 256
+ * T0 = 256 * log10(10 + 1.0) + 0.5
+ */
+ d = T0;
+ d = float64_div(d, 256, &env->fp_status);
+ d = float64_chs(d);
+ d = exp10(d); // XXX: use float emulation function
+ d = float64_add(d, 1.0, &env->fp_status);
+ d = log10(d); // XXX: use float emulation function
+ d = float64_mul(d, 256, &env->fp_status);
+ d = float64_add(d, 0.5, &env->fp_status);
+ T0 = float64_round_to_int(d, &env->fp_status);
#endif
+ } else {
+ T0 = 0;
+ }
}
/*****************************************************************************/
+/* Embedded PowerPC specific helpers */
+void do_405_check_ov (void)
+{
+ if (likely((((uint32_t)T1 ^ (uint32_t)T2) >> 31) ||
+ !(((uint32_t)T0 ^ (uint32_t)T2) >> 31))) {
+ xer_ov = 0;
+ } else {
+ xer_ov = 1;
+ xer_so = 1;
+ }
+}
+
+void do_405_check_sat (void)
+{
+ if (!likely((((uint32_t)T1 ^ (uint32_t)T2) >> 31) ||
+ !(((uint32_t)T0 ^ (uint32_t)T2) >> 31))) {
+ /* Saturate result */
+ if (T2 >> 31) {
+ T0 = INT32_MIN;
+ } else {
+ T0 = INT32_MAX;
+ }
+ }
+}
+
+#if !defined(CONFIG_USER_ONLY)
+void do_40x_rfci (void)
+{
+ env->nip = env->spr[SPR_40x_SRR2];
+ do_store_msr(env, env->spr[SPR_40x_SRR3] & ~0xFFFF0000);
+#if defined (DEBUG_OP)
+ cpu_dump_rfi(env->nip, do_load_msr(env));
+#endif
+ env->interrupt_request = CPU_INTERRUPT_EXITTB;
+}
+
+void do_rfci (void)
+{
+#if defined(TARGET_PPC64)
+ if (env->spr[SPR_BOOKE_CSRR1] & (1 << MSR_CM)) {
+ env->nip = (uint64_t)env->spr[SPR_BOOKE_CSRR0];
+ } else
+#endif
+ {
+ env->nip = (uint32_t)env->spr[SPR_BOOKE_CSRR0];
+ }
+ do_store_msr(env, (uint32_t)env->spr[SPR_BOOKE_CSRR1] & ~0x3FFF0000);
+#if defined (DEBUG_OP)
+ cpu_dump_rfi(env->nip, do_load_msr(env));
+#endif
+ env->interrupt_request = CPU_INTERRUPT_EXITTB;
+}
+
+void do_rfdi (void)
+{
+#if defined(TARGET_PPC64)
+ if (env->spr[SPR_BOOKE_DSRR1] & (1 << MSR_CM)) {
+ env->nip = (uint64_t)env->spr[SPR_BOOKE_DSRR0];
+ } else
+#endif
+ {
+ env->nip = (uint32_t)env->spr[SPR_BOOKE_DSRR0];
+ }
+ do_store_msr(env, (uint32_t)env->spr[SPR_BOOKE_DSRR1] & ~0x3FFF0000);
+#if defined (DEBUG_OP)
+ cpu_dump_rfi(env->nip, do_load_msr(env));
+#endif
+ env->interrupt_request = CPU_INTERRUPT_EXITTB;
+}
+
+void do_rfmci (void)
+{
+#if defined(TARGET_PPC64)
+ if (env->spr[SPR_BOOKE_MCSRR1] & (1 << MSR_CM)) {
+ env->nip = (uint64_t)env->spr[SPR_BOOKE_MCSRR0];
+ } else
+#endif
+ {
+ env->nip = (uint32_t)env->spr[SPR_BOOKE_MCSRR0];
+ }
+ do_store_msr(env, (uint32_t)env->spr[SPR_BOOKE_MCSRR1] & ~0x3FFF0000);
+#if defined (DEBUG_OP)
+ cpu_dump_rfi(env->nip, do_load_msr(env));
+#endif
+ env->interrupt_request = CPU_INTERRUPT_EXITTB;
+}
+
+void do_load_dcr (void)
+{
+ target_ulong val;
+
+ if (unlikely(env->dcr_env == NULL)) {
+ if (loglevel != 0) {
+ fprintf(logfile, "No DCR environment\n");
+ }
+ do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_INVAL);
+ } else if (unlikely(ppc_dcr_read(env->dcr_env, T0, &val) != 0)) {
+ if (loglevel != 0) {
+ fprintf(logfile, "DCR read error %d %03x\n", (int)T0, (int)T0);
+ }
+ do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_REG);
+ } else {
+ T0 = val;
+ }
+}
+
+void do_store_dcr (void)
+{
+ if (unlikely(env->dcr_env == NULL)) {
+ if (loglevel != 0) {
+ fprintf(logfile, "No DCR environment\n");
+ }
+ do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_INVAL);
+ } else if (unlikely(ppc_dcr_write(env->dcr_env, T0, T1) != 0)) {
+ if (loglevel != 0) {
+ fprintf(logfile, "DCR write error %d %03x\n", (int)T0, (int)T0);
+ }
+ do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_PRIV_REG);
+ }
+}
+
+void do_load_403_pb (int num)
+{
+ T0 = env->pb[num];
+}
+
+void do_store_403_pb (int num)
+{
+ if (likely(env->pb[num] != T0)) {
+ env->pb[num] = T0;
+ /* Should be optimized */
+ tlb_flush(env, 1);
+ }
+}
+#endif
+
+/* 440 specific */
+void do_440_dlmzb (void)
+{
+ target_ulong mask;
+ int i;
+
+ i = 1;
+ for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
+ if ((T0 & mask) == 0)
+ goto done;
+ i++;
+ }
+ for (mask = 0xFF000000; mask != 0; mask = mask >> 8) {
+ if ((T1 & mask) == 0)
+ break;
+ i++;
+ }
+ done:
+ T0 = i;
+}
+
+#if defined(TARGET_PPCEMB)
+/* SPE extension helpers */
+/* Use a table to make this quicker */
+static uint8_t hbrev[16] = {
+ 0x0, 0x8, 0x4, 0xC, 0x2, 0xA, 0x6, 0xE,
+ 0x1, 0x9, 0x5, 0xD, 0x3, 0xB, 0x7, 0xF,
+};
+
+static inline uint8_t byte_reverse (uint8_t val)
+{
+ return hbrev[val >> 4] | (hbrev[val & 0xF] << 4);
+}
+
+static inline uint32_t word_reverse (uint32_t val)
+{
+ return byte_reverse(val >> 24) | (byte_reverse(val >> 16) << 8) |
+ (byte_reverse(val >> 8) << 16) | (byte_reverse(val) << 24);
+}
+
+#define MASKBITS 16 // Random value - to be fixed
+void do_brinc (void)
+{
+ uint32_t a, b, d, mask;
+
+ mask = (uint32_t)(-1UL) >> MASKBITS;
+ b = T1_64 & mask;
+ a = T0_64 & mask;
+ d = word_reverse(1 + word_reverse(a | ~mask));
+ T0_64 = (T0_64 & ~mask) | (d & mask);
+}
+
+#define DO_SPE_OP2(name) \
+void do_ev##name (void) \
+{ \
+ T0_64 = ((uint64_t)_do_e##name(T0_64 >> 32, T1_64 >> 32) << 32) | \
+ (uint64_t)_do_e##name(T0_64, T1_64); \
+}
+
+#define DO_SPE_OP1(name) \
+void do_ev##name (void) \
+{ \
+ T0_64 = ((uint64_t)_do_e##name(T0_64 >> 32) << 32) | \
+ (uint64_t)_do_e##name(T0_64); \
+}
+
+/* Fixed-point vector arithmetic */
+static inline uint32_t _do_eabs (uint32_t val)
+{
+ if (val != 0x80000000)
+ val &= ~0x80000000;
+
+ return val;
+}
+
+static inline uint32_t _do_eaddw (uint32_t op1, uint32_t op2)
+{
+ return op1 + op2;
+}
+
+static inline int _do_ecntlsw (uint32_t val)
+{
+ if (val & 0x80000000)
+ return _do_cntlzw(~val);
+ else
+ return _do_cntlzw(val);
+}
+
+static inline int _do_ecntlzw (uint32_t val)
+{
+ return _do_cntlzw(val);
+}
+
+static inline uint32_t _do_eneg (uint32_t val)
+{
+ if (val != 0x80000000)
+ val ^= 0x80000000;
+
+ return val;
+}
+
+static inline uint32_t _do_erlw (uint32_t op1, uint32_t op2)
+{
+ return rotl32(op1, op2);
+}
+
+static inline uint32_t _do_erndw (uint32_t val)
+{
+ return (val + 0x000080000000) & 0xFFFF0000;
+}
+
+static inline uint32_t _do_eslw (uint32_t op1, uint32_t op2)
+{
+ /* No error here: 6 bits are used */
+ return op1 << (op2 & 0x3F);
+}
+
+static inline int32_t _do_esrws (int32_t op1, uint32_t op2)
+{
+ /* No error here: 6 bits are used */
+ return op1 >> (op2 & 0x3F);
+}
+
+static inline uint32_t _do_esrwu (uint32_t op1, uint32_t op2)
+{
+ /* No error here: 6 bits are used */
+ return op1 >> (op2 & 0x3F);
+}
+
+static inline uint32_t _do_esubfw (uint32_t op1, uint32_t op2)
+{
+ return op2 - op1;
+}
+
+/* evabs */
+DO_SPE_OP1(abs);
+/* evaddw */
+DO_SPE_OP2(addw);
+/* evcntlsw */
+DO_SPE_OP1(cntlsw);
+/* evcntlzw */
+DO_SPE_OP1(cntlzw);
+/* evneg */
+DO_SPE_OP1(neg);
+/* evrlw */
+DO_SPE_OP2(rlw);
+/* evrnd */
+DO_SPE_OP1(rndw);
+/* evslw */
+DO_SPE_OP2(slw);
+/* evsrws */
+DO_SPE_OP2(srws);
+/* evsrwu */
+DO_SPE_OP2(srwu);
+/* evsubfw */
+DO_SPE_OP2(subfw);
+
+/* evsel is a little bit more complicated... */
+static inline uint32_t _do_esel (uint32_t op1, uint32_t op2, int n)
+{
+ if (n)
+ return op1;
+ else
+ return op2;
+}
+
+void do_evsel (void)
+{
+ T0_64 = ((uint64_t)_do_esel(T0_64 >> 32, T1_64 >> 32, T0 >> 3) << 32) |
+ (uint64_t)_do_esel(T0_64, T1_64, (T0 >> 2) & 1);
+}
+
+/* Fixed-point vector comparisons */
+#define DO_SPE_CMP(name) \
+void do_ev##name (void) \
+{ \
+ T0 = _do_evcmp_merge((uint64_t)_do_e##name(T0_64 >> 32, \
+ T1_64 >> 32) << 32, \
+ _do_e##name(T0_64, T1_64)); \
+}
+
+static inline uint32_t _do_evcmp_merge (int t0, int t1)
+{
+ return (t0 << 3) | (t1 << 2) | ((t0 | t1) << 1) | (t0 & t1);
+}
+static inline int _do_ecmpeq (uint32_t op1, uint32_t op2)
+{
+ return op1 == op2 ? 1 : 0;
+}
+
+static inline int _do_ecmpgts (int32_t op1, int32_t op2)
+{
+ return op1 > op2 ? 1 : 0;
+}
+
+static inline int _do_ecmpgtu (uint32_t op1, uint32_t op2)
+{
+ return op1 > op2 ? 1 : 0;
+}
+
+static inline int _do_ecmplts (int32_t op1, int32_t op2)
+{
+ return op1 < op2 ? 1 : 0;
+}
+
+static inline int _do_ecmpltu (uint32_t op1, uint32_t op2)
+{
+ return op1 < op2 ? 1 : 0;
+}
+
+/* evcmpeq */
+DO_SPE_CMP(cmpeq);
+/* evcmpgts */
+DO_SPE_CMP(cmpgts);
+/* evcmpgtu */
+DO_SPE_CMP(cmpgtu);
+/* evcmplts */
+DO_SPE_CMP(cmplts);
+/* evcmpltu */
+DO_SPE_CMP(cmpltu);
+
+/* Single precision floating-point conversions from/to integer */
+static inline uint32_t _do_efscfsi (int32_t val)
+{
+ union {
+ uint32_t u;
+ float32 f;
+ } u;
+
+ u.f = int32_to_float32(val, &env->spe_status);
+
+ return u.u;
+}
+
+static inline uint32_t _do_efscfui (uint32_t val)
+{
+ union {
+ uint32_t u;
+ float32 f;
+ } u;
+
+ u.f = uint32_to_float32(val, &env->spe_status);
+
+ return u.u;
+}
+
+static inline int32_t _do_efsctsi (uint32_t val)
+{
+ union {
+ int32_t u;
+ float32 f;
+ } u;
+
+ u.u = val;
+ /* NaN are not treated the same way IEEE 754 does */
+ if (unlikely(isnan(u.f)))
+ return 0;
+
+ return float32_to_int32(u.f, &env->spe_status);
+}
+
+static inline uint32_t _do_efsctui (uint32_t val)
+{
+ union {
+ int32_t u;
+ float32 f;
+ } u;
+
+ u.u = val;
+ /* NaN are not treated the same way IEEE 754 does */
+ if (unlikely(isnan(u.f)))
+ return 0;
+
+ return float32_to_uint32(u.f, &env->spe_status);
+}
+
+static inline int32_t _do_efsctsiz (uint32_t val)
+{
+ union {
+ int32_t u;
+ float32 f;
+ } u;
+
+ u.u = val;
+ /* NaN are not treated the same way IEEE 754 does */
+ if (unlikely(isnan(u.f)))
+ return 0;
+
+ return float32_to_int32_round_to_zero(u.f, &env->spe_status);
+}
+
+static inline uint32_t _do_efsctuiz (uint32_t val)
+{
+ union {
+ int32_t u;
+ float32 f;
+ } u;
+
+ u.u = val;
+ /* NaN are not treated the same way IEEE 754 does */
+ if (unlikely(isnan(u.f)))
+ return 0;
+
+ return float32_to_uint32_round_to_zero(u.f, &env->spe_status);
+}
+
+void do_efscfsi (void)
+{
+ T0_64 = _do_efscfsi(T0_64);
+}
+
+void do_efscfui (void)
+{
+ T0_64 = _do_efscfui(T0_64);
+}
+
+void do_efsctsi (void)
+{
+ T0_64 = _do_efsctsi(T0_64);
+}
+
+void do_efsctui (void)
+{
+ T0_64 = _do_efsctui(T0_64);
+}
+
+void do_efsctsiz (void)
+{
+ T0_64 = _do_efsctsiz(T0_64);
+}
+
+void do_efsctuiz (void)
+{
+ T0_64 = _do_efsctuiz(T0_64);
+}
+
+/* Single precision floating-point conversion to/from fractional */
+static inline uint32_t _do_efscfsf (uint32_t val)
+{
+ union {
+ uint32_t u;
+ float32 f;
+ } u;
+ float32 tmp;
+
+ u.f = int32_to_float32(val, &env->spe_status);
+ tmp = int64_to_float32(1ULL << 32, &env->spe_status);
+ u.f = float32_div(u.f, tmp, &env->spe_status);
+
+ return u.u;
+}
+
+static inline uint32_t _do_efscfuf (uint32_t val)
+{
+ union {
+ uint32_t u;
+ float32 f;
+ } u;
+ float32 tmp;
+
+ u.f = uint32_to_float32(val, &env->spe_status);
+ tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
+ u.f = float32_div(u.f, tmp, &env->spe_status);
+
+ return u.u;
+}
+
+static inline int32_t _do_efsctsf (uint32_t val)
+{
+ union {
+ int32_t u;
+ float32 f;
+ } u;
+ float32 tmp;
+
+ u.u = val;
+ /* NaN are not treated the same way IEEE 754 does */
+ if (unlikely(isnan(u.f)))
+ return 0;
+ tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
+ u.f = float32_mul(u.f, tmp, &env->spe_status);
+
+ return float32_to_int32(u.f, &env->spe_status);
+}
+
+static inline uint32_t _do_efsctuf (uint32_t val)
+{
+ union {
+ int32_t u;
+ float32 f;
+ } u;
+ float32 tmp;
+
+ u.u = val;
+ /* NaN are not treated the same way IEEE 754 does */
+ if (unlikely(isnan(u.f)))
+ return 0;
+ tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
+ u.f = float32_mul(u.f, tmp, &env->spe_status);
+
+ return float32_to_uint32(u.f, &env->spe_status);
+}
+
+static inline int32_t _do_efsctsfz (uint32_t val)
+{
+ union {
+ int32_t u;
+ float32 f;
+ } u;
+ float32 tmp;
+
+ u.u = val;
+ /* NaN are not treated the same way IEEE 754 does */
+ if (unlikely(isnan(u.f)))
+ return 0;
+ tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
+ u.f = float32_mul(u.f, tmp, &env->spe_status);
+
+ return float32_to_int32_round_to_zero(u.f, &env->spe_status);
+}
+
+static inline uint32_t _do_efsctufz (uint32_t val)
+{
+ union {
+ int32_t u;
+ float32 f;
+ } u;
+ float32 tmp;
+
+ u.u = val;
+ /* NaN are not treated the same way IEEE 754 does */
+ if (unlikely(isnan(u.f)))
+ return 0;
+ tmp = uint64_to_float32(1ULL << 32, &env->spe_status);
+ u.f = float32_mul(u.f, tmp, &env->spe_status);
+
+ return float32_to_uint32_round_to_zero(u.f, &env->spe_status);
+}
+
+void do_efscfsf (void)
+{
+ T0_64 = _do_efscfsf(T0_64);
+}
+
+void do_efscfuf (void)
+{
+ T0_64 = _do_efscfuf(T0_64);
+}
+
+void do_efsctsf (void)
+{
+ T0_64 = _do_efsctsf(T0_64);
+}
+
+void do_efsctuf (void)
+{
+ T0_64 = _do_efsctuf(T0_64);
+}
+
+void do_efsctsfz (void)
+{
+ T0_64 = _do_efsctsfz(T0_64);
+}
+
+void do_efsctufz (void)
+{
+ T0_64 = _do_efsctufz(T0_64);
+}
+
+/* Double precision floating point helpers */
+static inline int _do_efdcmplt (uint64_t op1, uint64_t op2)
+{
+ /* XXX: TODO: test special values (NaN, infinites, ...) */
+ return _do_efdtstlt(op1, op2);
+}
+
+static inline int _do_efdcmpgt (uint64_t op1, uint64_t op2)
+{
+ /* XXX: TODO: test special values (NaN, infinites, ...) */
+ return _do_efdtstgt(op1, op2);
+}
+
+static inline int _do_efdcmpeq (uint64_t op1, uint64_t op2)
+{
+ /* XXX: TODO: test special values (NaN, infinites, ...) */
+ return _do_efdtsteq(op1, op2);
+}
+
+void do_efdcmplt (void)
+{
+ T0 = _do_efdcmplt(T0_64, T1_64);
+}
+
+void do_efdcmpgt (void)
+{
+ T0 = _do_efdcmpgt(T0_64, T1_64);
+}
+
+void do_efdcmpeq (void)
+{
+ T0 = _do_efdcmpeq(T0_64, T1_64);
+}
+
+/* Double precision floating-point conversion to/from integer */
+static inline uint64_t _do_efdcfsi (int64_t val)
+{
+ union {
+ uint64_t u;
+ float64 f;
+ } u;
+
+ u.f = int64_to_float64(val, &env->spe_status);
+
+ return u.u;
+}
+
+static inline uint64_t _do_efdcfui (uint64_t val)
+{
+ union {
+ uint64_t u;
+ float64 f;
+ } u;
+
+ u.f = uint64_to_float64(val, &env->spe_status);
+
+ return u.u;
+}
+
+static inline int64_t _do_efdctsi (uint64_t val)
+{
+ union {
+ int64_t u;
+ float64 f;
+ } u;
+
+ u.u = val;
+ /* NaN are not treated the same way IEEE 754 does */
+ if (unlikely(isnan(u.f)))
+ return 0;
+
+ return float64_to_int64(u.f, &env->spe_status);
+}
+
+static inline uint64_t _do_efdctui (uint64_t val)
+{
+ union {
+ int64_t u;
+ float64 f;
+ } u;
+
+ u.u = val;
+ /* NaN are not treated the same way IEEE 754 does */
+ if (unlikely(isnan(u.f)))
+ return 0;
+
+ return float64_to_uint64(u.f, &env->spe_status);
+}
+
+static inline int64_t _do_efdctsiz (uint64_t val)
+{
+ union {
+ int64_t u;
+ float64 f;
+ } u;
+
+ u.u = val;
+ /* NaN are not treated the same way IEEE 754 does */
+ if (unlikely(isnan(u.f)))
+ return 0;
+
+ return float64_to_int64_round_to_zero(u.f, &env->spe_status);
+}
+
+static inline uint64_t _do_efdctuiz (uint64_t val)
+{
+ union {
+ int64_t u;
+ float64 f;
+ } u;
+
+ u.u = val;
+ /* NaN are not treated the same way IEEE 754 does */
+ if (unlikely(isnan(u.f)))
+ return 0;
+
+ return float64_to_uint64_round_to_zero(u.f, &env->spe_status);
+}
+
+void do_efdcfsi (void)
+{
+ T0_64 = _do_efdcfsi(T0_64);
+}
+
+void do_efdcfui (void)
+{
+ T0_64 = _do_efdcfui(T0_64);
+}
+
+void do_efdctsi (void)
+{
+ T0_64 = _do_efdctsi(T0_64);
+}
+
+void do_efdctui (void)
+{
+ T0_64 = _do_efdctui(T0_64);
+}
+
+void do_efdctsiz (void)
+{
+ T0_64 = _do_efdctsiz(T0_64);
+}
+
+void do_efdctuiz (void)
+{
+ T0_64 = _do_efdctuiz(T0_64);
+}
+
+/* Double precision floating-point conversion to/from fractional */
+static inline uint64_t _do_efdcfsf (int64_t val)
+{
+ union {
+ uint64_t u;
+ float64 f;
+ } u;
+ float64 tmp;
+
+ u.f = int32_to_float64(val, &env->spe_status);
+ tmp = int64_to_float64(1ULL << 32, &env->spe_status);
+ u.f = float64_div(u.f, tmp, &env->spe_status);
+
+ return u.u;
+}
+
+static inline uint64_t _do_efdcfuf (uint64_t val)
+{
+ union {
+ uint64_t u;
+ float64 f;
+ } u;
+ float64 tmp;
+
+ u.f = uint32_to_float64(val, &env->spe_status);
+ tmp = int64_to_float64(1ULL << 32, &env->spe_status);
+ u.f = float64_div(u.f, tmp, &env->spe_status);
+
+ return u.u;
+}
+
+static inline int64_t _do_efdctsf (uint64_t val)
+{
+ union {
+ int64_t u;
+ float64 f;
+ } u;
+ float64 tmp;
+
+ u.u = val;
+ /* NaN are not treated the same way IEEE 754 does */
+ if (unlikely(isnan(u.f)))
+ return 0;
+ tmp = uint64_to_float64(1ULL << 32, &env->spe_status);
+ u.f = float64_mul(u.f, tmp, &env->spe_status);
+
+ return float64_to_int32(u.f, &env->spe_status);
+}
+
+static inline uint64_t _do_efdctuf (uint64_t val)
+{
+ union {
+ int64_t u;
+ float64 f;
+ } u;
+ float64 tmp;
+
+ u.u = val;
+ /* NaN are not treated the same way IEEE 754 does */
+ if (unlikely(isnan(u.f)))
+ return 0;
+ tmp = uint64_to_float64(1ULL << 32, &env->spe_status);
+ u.f = float64_mul(u.f, tmp, &env->spe_status);
+
+ return float64_to_uint32(u.f, &env->spe_status);
+}
+
+static inline int64_t _do_efdctsfz (uint64_t val)
+{
+ union {
+ int64_t u;
+ float64 f;
+ } u;
+ float64 tmp;
+
+ u.u = val;
+ /* NaN are not treated the same way IEEE 754 does */
+ if (unlikely(isnan(u.f)))
+ return 0;
+ tmp = uint64_to_float64(1ULL << 32, &env->spe_status);
+ u.f = float64_mul(u.f, tmp, &env->spe_status);
+
+ return float64_to_int32_round_to_zero(u.f, &env->spe_status);
+}
+
+static inline uint64_t _do_efdctufz (uint64_t val)
+{
+ union {
+ int64_t u;
+ float64 f;
+ } u;
+ float64 tmp;
+
+ u.u = val;
+ /* NaN are not treated the same way IEEE 754 does */
+ if (unlikely(isnan(u.f)))
+ return 0;
+ tmp = uint64_to_float64(1ULL << 32, &env->spe_status);
+ u.f = float64_mul(u.f, tmp, &env->spe_status);
+
+ return float64_to_uint32_round_to_zero(u.f, &env->spe_status);
+}
+
+void do_efdcfsf (void)
+{
+ T0_64 = _do_efdcfsf(T0_64);
+}
+
+void do_efdcfuf (void)
+{
+ T0_64 = _do_efdcfuf(T0_64);
+}
+
+void do_efdctsf (void)
+{
+ T0_64 = _do_efdctsf(T0_64);
+}
+
+void do_efdctuf (void)
+{
+ T0_64 = _do_efdctuf(T0_64);
+}
+
+void do_efdctsfz (void)
+{
+ T0_64 = _do_efdctsfz(T0_64);
+}
+
+void do_efdctufz (void)
+{
+ T0_64 = _do_efdctufz(T0_64);
+}
+
+/* Floating point conversion between single and double precision */
+static inline uint32_t _do_efscfd (uint64_t val)
+{
+ union {
+ uint64_t u;
+ float64 f;
+ } u1;
+ union {
+ uint32_t u;
+ float32 f;
+ } u2;
+
+ u1.u = val;
+ u2.f = float64_to_float32(u1.f, &env->spe_status);
+
+ return u2.u;
+}
+
+static inline uint64_t _do_efdcfs (uint32_t val)
+{
+ union {
+ uint64_t u;
+ float64 f;
+ } u2;
+ union {
+ uint32_t u;
+ float32 f;
+ } u1;
+
+ u1.u = val;
+ u2.f = float32_to_float64(u1.f, &env->spe_status);
+
+ return u2.u;
+}
+
+void do_efscfd (void)
+{
+ T0_64 = _do_efscfd(T0_64);
+}
+
+void do_efdcfs (void)
+{
+ T0_64 = _do_efdcfs(T0_64);
+}
+
+/* Single precision fixed-point vector arithmetic */
+/* evfsabs */
+DO_SPE_OP1(fsabs);
+/* evfsnabs */
+DO_SPE_OP1(fsnabs);
+/* evfsneg */
+DO_SPE_OP1(fsneg);
+/* evfsadd */
+DO_SPE_OP2(fsadd);
+/* evfssub */
+DO_SPE_OP2(fssub);
+/* evfsmul */
+DO_SPE_OP2(fsmul);
+/* evfsdiv */
+DO_SPE_OP2(fsdiv);
+
+/* Single-precision floating-point comparisons */
+static inline int _do_efscmplt (uint32_t op1, uint32_t op2)
+{
+ /* XXX: TODO: test special values (NaN, infinites, ...) */
+ return _do_efststlt(op1, op2);
+}
+
+static inline int _do_efscmpgt (uint32_t op1, uint32_t op2)
+{
+ /* XXX: TODO: test special values (NaN, infinites, ...) */
+ return _do_efststgt(op1, op2);
+}
+
+static inline int _do_efscmpeq (uint32_t op1, uint32_t op2)
+{
+ /* XXX: TODO: test special values (NaN, infinites, ...) */
+ return _do_efststeq(op1, op2);
+}
+
+void do_efscmplt (void)
+{
+ T0 = _do_efscmplt(T0_64, T1_64);
+}
+
+void do_efscmpgt (void)
+{
+ T0 = _do_efscmpgt(T0_64, T1_64);
+}
+
+void do_efscmpeq (void)
+{
+ T0 = _do_efscmpeq(T0_64, T1_64);
+}
+
+/* Single-precision floating-point vector comparisons */
+/* evfscmplt */
+DO_SPE_CMP(fscmplt);
+/* evfscmpgt */
+DO_SPE_CMP(fscmpgt);
+/* evfscmpeq */
+DO_SPE_CMP(fscmpeq);
+/* evfststlt */
+DO_SPE_CMP(fststlt);
+/* evfststgt */
+DO_SPE_CMP(fststgt);
+/* evfststeq */
+DO_SPE_CMP(fststeq);
+
+/* Single-precision floating-point vector conversions */
+/* evfscfsi */
+DO_SPE_OP1(fscfsi);
+/* evfscfui */
+DO_SPE_OP1(fscfui);
+/* evfscfuf */
+DO_SPE_OP1(fscfuf);
+/* evfscfsf */
+DO_SPE_OP1(fscfsf);
+/* evfsctsi */
+DO_SPE_OP1(fsctsi);
+/* evfsctui */
+DO_SPE_OP1(fsctui);
+/* evfsctsiz */
+DO_SPE_OP1(fsctsiz);
+/* evfsctuiz */
+DO_SPE_OP1(fsctuiz);
+/* evfsctsf */
+DO_SPE_OP1(fsctsf);
+/* evfsctuf */
+DO_SPE_OP1(fsctuf);
+#endif /* defined(TARGET_PPCEMB) */
+
+/*****************************************************************************/
/* Softmmu support */
#if !defined (CONFIG_USER_ONLY)
@@ -570,7 +2238,7 @@
saved_env = env;
env = cpu_single_env;
ret = cpu_ppc_handle_mmu_fault(env, addr, is_write, is_user, 1);
- if (!likely(ret == 0)) {
+ if (unlikely(ret != 0)) {
if (likely(retaddr)) {
/* now we have a real cpu fault */
pc = (target_phys_addr_t)retaddr;
@@ -579,11 +2247,365 @@
/* the PC is inside the translated code. It means that we have
a virtual CPU fault */
cpu_restore_state(tb, env, pc, NULL);
-}
+ }
}
do_raise_exception_err(env->exception_index, env->error_code);
}
env = saved_env;
}
+
+/* TLB invalidation helpers */
+void do_tlbia (void)
+{
+ ppc_tlb_invalidate_all(env);
+}
+
+void do_tlbie (void)
+{
+ T0 = (uint32_t)T0;
+#if !defined(FLUSH_ALL_TLBS)
+ if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_6xx)) {
+ ppc6xx_tlb_invalidate_virt(env, T0 & TARGET_PAGE_MASK, 0);
+ if (env->id_tlbs == 1)
+ ppc6xx_tlb_invalidate_virt(env, T0 & TARGET_PAGE_MASK, 1);
+ } else if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_4xx)) {
+ /* XXX: TODO */
+#if 0
+ ppcbooke_tlb_invalidate_virt(env, T0 & TARGET_PAGE_MASK,
+ env->spr[SPR_BOOKE_PID]);
+#endif
+ } else {
+ /* tlbie invalidate TLBs for all segments */
+ T0 &= TARGET_PAGE_MASK;
+ T0 &= ~((target_ulong)-1 << 28);
+ /* XXX: this case should be optimized,
+ * giving a mask to tlb_flush_page
+ */
+ tlb_flush_page(env, T0 | (0x0 << 28));
+ tlb_flush_page(env, T0 | (0x1 << 28));
+ tlb_flush_page(env, T0 | (0x2 << 28));
+ tlb_flush_page(env, T0 | (0x3 << 28));
+ tlb_flush_page(env, T0 | (0x4 << 28));
+ tlb_flush_page(env, T0 | (0x5 << 28));
+ tlb_flush_page(env, T0 | (0x6 << 28));
+ tlb_flush_page(env, T0 | (0x7 << 28));
+ tlb_flush_page(env, T0 | (0x8 << 28));
+ tlb_flush_page(env, T0 | (0x9 << 28));
+ tlb_flush_page(env, T0 | (0xA << 28));
+ tlb_flush_page(env, T0 | (0xB << 28));
+ tlb_flush_page(env, T0 | (0xC << 28));
+ tlb_flush_page(env, T0 | (0xD << 28));
+ tlb_flush_page(env, T0 | (0xE << 28));
+ tlb_flush_page(env, T0 | (0xF << 28));
+ }
+#else
+ do_tlbia();
+#endif
+}
+
+#if defined(TARGET_PPC64)
+void do_tlbie_64 (void)
+{
+ T0 = (uint64_t)T0;
+#if !defined(FLUSH_ALL_TLBS)
+ if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_6xx)) {
+ ppc6xx_tlb_invalidate_virt(env, T0 & TARGET_PAGE_MASK, 0);
+ if (env->id_tlbs == 1)
+ ppc6xx_tlb_invalidate_virt(env, T0 & TARGET_PAGE_MASK, 1);
+ } else if (unlikely(PPC_MMU(env) == PPC_FLAGS_MMU_SOFT_4xx)) {
+ /* XXX: TODO */
+#if 0
+ ppcbooke_tlb_invalidate_virt(env, T0 & TARGET_PAGE_MASK,
+ env->spr[SPR_BOOKE_PID]);
+#endif
+ } else {
+ /* tlbie invalidate TLBs for all segments
+ * As we have 2^36 segments, invalidate all qemu TLBs
+ */
+#if 0
+ T0 &= TARGET_PAGE_MASK;
+ T0 &= ~((target_ulong)-1 << 28);
+ /* XXX: this case should be optimized,
+ * giving a mask to tlb_flush_page
+ */
+ tlb_flush_page(env, T0 | (0x0 << 28));
+ tlb_flush_page(env, T0 | (0x1 << 28));
+ tlb_flush_page(env, T0 | (0x2 << 28));
+ tlb_flush_page(env, T0 | (0x3 << 28));
+ tlb_flush_page(env, T0 | (0x4 << 28));
+ tlb_flush_page(env, T0 | (0x5 << 28));
+ tlb_flush_page(env, T0 | (0x6 << 28));
+ tlb_flush_page(env, T0 | (0x7 << 28));
+ tlb_flush_page(env, T0 | (0x8 << 28));
+ tlb_flush_page(env, T0 | (0x9 << 28));
+ tlb_flush_page(env, T0 | (0xA << 28));
+ tlb_flush_page(env, T0 | (0xB << 28));
+ tlb_flush_page(env, T0 | (0xC << 28));
+ tlb_flush_page(env, T0 | (0xD << 28));
+ tlb_flush_page(env, T0 | (0xE << 28));
+ tlb_flush_page(env, T0 | (0xF << 28));
+#else
+ tlb_flush(env, 1);
+#endif
+ }
+#else
+ do_tlbia();
+#endif
+}
+#endif
+
+#if defined(TARGET_PPC64)
+void do_slbia (void)
+{
+ /* XXX: TODO */
+ tlb_flush(env, 1);
+}
+
+void do_slbie (void)
+{
+ /* XXX: TODO */
+ tlb_flush(env, 1);
+}
+#endif
+
+/* Software driven TLBs management */
+/* PowerPC 602/603 software TLB load instructions helpers */
+void do_load_6xx_tlb (int is_code)
+{
+ target_ulong RPN, CMP, EPN;
+ int way;
+
+ RPN = env->spr[SPR_RPA];
+ if (is_code) {
+ CMP = env->spr[SPR_ICMP];
+ EPN = env->spr[SPR_IMISS];
+ } else {
+ CMP = env->spr[SPR_DCMP];
+ EPN = env->spr[SPR_DMISS];
+ }
+ way = (env->spr[SPR_SRR1] >> 17) & 1;
+#if defined (DEBUG_SOFTWARE_TLB)
+ if (loglevel != 0) {
+ fprintf(logfile, "%s: EPN %08lx %08lx PTE0 %08lx PTE1 %08lx way %d\n",
+ __func__, (unsigned long)T0, (unsigned long)EPN,
+ (unsigned long)CMP, (unsigned long)RPN, way);
+ }
+#endif
+ /* Store this TLB */
+ ppc6xx_tlb_store(env, (uint32_t)(T0 & TARGET_PAGE_MASK),
+ way, is_code, CMP, RPN);
+}
+
+static target_ulong booke_tlb_to_page_size (int size)
+{
+ return 1024 << (2 * size);
+}
+
+static int booke_page_size_to_tlb (target_ulong page_size)
+{
+ int size;
+
+ switch (page_size) {
+ case 0x00000400UL:
+ size = 0x0;
+ break;
+ case 0x00001000UL:
+ size = 0x1;
+ break;
+ case 0x00004000UL:
+ size = 0x2;
+ break;
+ case 0x00010000UL:
+ size = 0x3;
+ break;
+ case 0x00040000UL:
+ size = 0x4;
+ break;
+ case 0x00100000UL:
+ size = 0x5;
+ break;
+ case 0x00400000UL:
+ size = 0x6;
+ break;
+ case 0x01000000UL:
+ size = 0x7;
+ break;
+ case 0x04000000UL:
+ size = 0x8;
+ break;
+ case 0x10000000UL:
+ size = 0x9;
+ break;
+ case 0x40000000UL:
+ size = 0xA;
+ break;
+#if defined (TARGET_PPC64)
+ case 0x000100000000ULL:
+ size = 0xB;
+ break;
+ case 0x000400000000ULL:
+ size = 0xC;
+ break;
+ case 0x001000000000ULL:
+ size = 0xD;
+ break;
+ case 0x004000000000ULL:
+ size = 0xE;
+ break;
+ case 0x010000000000ULL:
+ size = 0xF;
+ break;
+#endif
+ default:
+ size = -1;
+ break;
+ }
+
+ return size;
+}
+
+/* Helpers for 4xx TLB management */
+void do_4xx_tlbre_lo (void)
+{
+ ppcemb_tlb_t *tlb;
+ int size;
+
+ T0 &= 0x3F;
+ tlb = &env->tlb[T0].tlbe;
+ T0 = tlb->EPN;
+ if (tlb->prot & PAGE_VALID)
+ T0 |= 0x400;
+ size = booke_page_size_to_tlb(tlb->size);
+ if (size < 0 || size > 0x7)
+ size = 1;
+ T0 |= size << 7;
+ env->spr[SPR_40x_PID] = tlb->PID;
+}
+
+void do_4xx_tlbre_hi (void)
+{
+ ppcemb_tlb_t *tlb;
+
+ T0 &= 0x3F;
+ tlb = &env->tlb[T0].tlbe;
+ T0 = tlb->RPN;
+ if (tlb->prot & PAGE_EXEC)
+ T0 |= 0x200;
+ if (tlb->prot & PAGE_WRITE)
+ T0 |= 0x100;
+}
+
+void do_4xx_tlbsx (void)
+{
+ T0 = ppcemb_tlb_search(env, T0);
+}
+
+void do_4xx_tlbsx_ (void)
+{
+ int tmp = xer_ov;
+
+ T0 = ppcemb_tlb_search(env, T0);
+ if (T0 != -1)
+ tmp |= 0x02;
+ env->crf[0] = tmp;
+}
+
+void do_4xx_tlbwe_hi (void)
+{
+ ppcemb_tlb_t *tlb;
+ target_ulong page, end;
+
+#if defined (DEBUG_SOFTWARE_TLB)
+ if (loglevel != 0) {
+ fprintf(logfile, "%s T0 " REGX " T1 " REGX "\n", __func__, T0, T1);
+ }
+#endif
+ T0 &= 0x3F;
+ tlb = &env->tlb[T0].tlbe;
+ /* Invalidate previous TLB (if it's valid) */
+ if (tlb->prot & PAGE_VALID) {
+ end = tlb->EPN + tlb->size;
+#if defined (DEBUG_SOFTWARE_TLB)
+ if (loglevel != 0) {
+ fprintf(logfile, "%s: invalidate old TLB %d start " ADDRX
+ " end " ADDRX "\n", __func__, (int)T0, tlb->EPN, end);
+ }
+#endif
+ for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
+ tlb_flush_page(env, page);
+ }
+ tlb->size = booke_tlb_to_page_size((T1 >> 7) & 0x7);
+ /* We cannot handle TLB size < TARGET_PAGE_SIZE.
+ * If this ever occurs, one should use the ppcemb target instead
+ * of the ppc or ppc64 one
+ */
+ if ((T1 & 0x40) && tlb->size < TARGET_PAGE_SIZE) {
+ cpu_abort(env, "TLB size %u < %u are not supported (%d)\n",
+ tlb->size, TARGET_PAGE_SIZE, (int)((T1 >> 7) & 0x7));
+ }
+ tlb->EPN = (T1 & 0xFFFFFC00) & ~(tlb->size - 1);
+ if (T1 & 0x40)
+ tlb->prot |= PAGE_VALID;
+ else
+ tlb->prot &= ~PAGE_VALID;
+ if (T1 & 0x20) {
+ /* XXX: TO BE FIXED */
+ cpu_abort(env, "Little-endian TLB entries are not supported by now\n");
+ }
+ tlb->PID = env->spr[SPR_40x_PID]; /* PID */
+ tlb->attr = T1 & 0xFF;
+#if defined (DEBUG_SOFTWARE_TLB)
+ if (loglevel != 0) {
+ fprintf(logfile, "%s: set up TLB %d RPN " PADDRX " EPN " ADDRX
+ " size " ADDRX " prot %c%c%c%c PID %d\n", __func__,
+ (int)T0, tlb->RPN, tlb->EPN, tlb->size,
+ tlb->prot & PAGE_READ ? 'r' : '-',
+ tlb->prot & PAGE_WRITE ? 'w' : '-',
+ tlb->prot & PAGE_EXEC ? 'x' : '-',
+ tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
+ }
+#endif
+ /* Invalidate new TLB (if valid) */
+ if (tlb->prot & PAGE_VALID) {
+ end = tlb->EPN + tlb->size;
+#if defined (DEBUG_SOFTWARE_TLB)
+ if (loglevel != 0) {
+ fprintf(logfile, "%s: invalidate TLB %d start " ADDRX
+ " end " ADDRX "\n", __func__, (int)T0, tlb->EPN, end);
+ }
+#endif
+ for (page = tlb->EPN; page < end; page += TARGET_PAGE_SIZE)
+ tlb_flush_page(env, page);
+ }
+}
+
+void do_4xx_tlbwe_lo (void)
+{
+ ppcemb_tlb_t *tlb;
+
+#if defined (DEBUG_SOFTWARE_TLB)
+ if (loglevel != 0) {
+ fprintf(logfile, "%s T0 " REGX " T1 " REGX "\n", __func__, T0, T1);
+ }
+#endif
+ T0 &= 0x3F;
+ tlb = &env->tlb[T0].tlbe;
+ tlb->RPN = T1 & 0xFFFFFC00;
+ tlb->prot = PAGE_READ;
+ if (T1 & 0x200)
+ tlb->prot |= PAGE_EXEC;
+ if (T1 & 0x100)
+ tlb->prot |= PAGE_WRITE;
+#if defined (DEBUG_SOFTWARE_TLB)
+ if (loglevel != 0) {
+ fprintf(logfile, "%s: set up TLB %d RPN " PADDRX " EPN " ADDRX
+ " size " ADDRX " prot %c%c%c%c PID %d\n", __func__,
+ (int)T0, tlb->RPN, tlb->EPN, tlb->size,
+ tlb->prot & PAGE_READ ? 'r' : '-',
+ tlb->prot & PAGE_WRITE ? 'w' : '-',
+ tlb->prot & PAGE_EXEC ? 'x' : '-',
+ tlb->prot & PAGE_VALID ? 'v' : '-', (int)tlb->PID);
+ }
+#endif
+}
#endif /* !CONFIG_USER_ONLY */
-
Added: trunk/src/host/qemu-neo1973/target-ppc/op_helper.h
===================================================================
--- trunk/src/host/qemu-neo1973/target-ppc/op_helper.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/target-ppc/op_helper.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,463 @@
+/*
+ * PowerPC emulation helpers header for qemu.
+ *
+ * Copyright (c) 2003-2007 Jocelyn Mayer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#if defined(MEMSUFFIX)
+
+/* Memory load/store helpers */
+void glue(do_lsw, MEMSUFFIX) (int dst);
+void glue(do_lsw_le, MEMSUFFIX) (int dst);
+void glue(do_stsw, MEMSUFFIX) (int src);
+void glue(do_stsw_le, MEMSUFFIX) (int src);
+void glue(do_lmw, MEMSUFFIX) (int dst);
+void glue(do_lmw_le, MEMSUFFIX) (int dst);
+void glue(do_stmw, MEMSUFFIX) (int src);
+void glue(do_stmw_le, MEMSUFFIX) (int src);
+void glue(do_icbi, MEMSUFFIX) (void);
+void glue(do_POWER_lscbx, MEMSUFFIX) (int dest, int ra, int rb);
+void glue(do_POWER2_lfq, MEMSUFFIX) (void);
+void glue(do_POWER2_lfq_le, MEMSUFFIX) (void);
+void glue(do_POWER2_stfq, MEMSUFFIX) (void);
+void glue(do_POWER2_stfq_le, MEMSUFFIX) (void);
+
+#if defined(TARGET_PPC64)
+void glue(do_lsw_64, MEMSUFFIX) (int dst);
+void glue(do_lsw_le_64, MEMSUFFIX) (int dst);
+void glue(do_stsw_64, MEMSUFFIX) (int src);
+void glue(do_stsw_le_64, MEMSUFFIX) (int src);
+void glue(do_lmw_64, MEMSUFFIX) (int dst);
+void glue(do_lmw_le_64, MEMSUFFIX) (int dst);
+void glue(do_stmw_64, MEMSUFFIX) (int src);
+void glue(do_stmw_le_64, MEMSUFFIX) (int src);
+void glue(do_icbi_64, MEMSUFFIX) (void);
+#endif
+
+#else
+
+void do_print_mem_EA (target_ulong EA);
+
+/* Registers load and stores */
+void do_load_cr (void);
+void do_store_cr (uint32_t mask);
+void do_load_xer (void);
+void do_store_xer (void);
+void do_load_fpscr (void);
+void do_store_fpscr (uint32_t mask);
+target_ulong ppc_load_dump_spr (int sprn);
+void ppc_store_dump_spr (int sprn, target_ulong val);
+
+/* Integer arithmetic helpers */
+void do_adde (void);
+void do_addmeo (void);
+void do_divwo (void);
+void do_divwuo (void);
+void do_mullwo (void);
+void do_nego (void);
+void do_subfe (void);
+void do_subfmeo (void);
+void do_subfzeo (void);
+void do_sraw (void);
+#if defined(TARGET_PPC64)
+void do_adde_64 (void);
+void do_addmeo_64 (void);
+void do_imul64 (uint64_t *tl, uint64_t *th);
+void do_mul64 (uint64_t *tl, uint64_t *th);
+void do_divdo (void);
+void do_divduo (void);
+void do_mulldo (void);
+void do_nego_64 (void);
+void do_subfe_64 (void);
+void do_subfmeo_64 (void);
+void do_subfzeo_64 (void);
+void do_srad (void);
+#endif
+void do_popcntb (void);
+#if defined(TARGET_PPC64)
+void do_popcntb_64 (void);
+#endif
+
+/* Floating-point arithmetic helpers */
+void do_fsqrt (void);
+void do_fres (void);
+void do_frsqrte (void);
+void do_fsel (void);
+#if USE_PRECISE_EMULATION
+void do_fmadd (void);
+void do_fmsub (void);
+#endif
+void do_fnmadd (void);
+void do_fnmsub (void);
+void do_fctiw (void);
+void do_fctiwz (void);
+#if defined(TARGET_PPC64)
+void do_fcfid (void);
+void do_fctid (void);
+void do_fctidz (void);
+#endif
+void do_fcmpu (void);
+void do_fcmpo (void);
+
+/* Misc */
+void do_tw (int flags);
+#if defined(TARGET_PPC64)
+void do_td (int flags);
+#endif
+#if !defined(CONFIG_USER_ONLY)
+void do_rfi (void);
+#if defined(TARGET_PPC64)
+void do_rfid (void);
+#endif
+void do_tlbia (void);
+void do_tlbie (void);
+#if defined(TARGET_PPC64)
+void do_tlbie_64 (void);
+#endif
+void do_load_6xx_tlb (int is_code);
+#if defined(TARGET_PPC64)
+void do_slbia (void);
+void do_slbie (void);
+#endif
+#endif
+
+/* POWER / PowerPC 601 specific helpers */
+void do_store_601_batu (int nr);
+void do_POWER_abso (void);
+void do_POWER_clcs (void);
+void do_POWER_div (void);
+void do_POWER_divo (void);
+void do_POWER_divs (void);
+void do_POWER_divso (void);
+void do_POWER_dozo (void);
+void do_POWER_maskg (void);
+void do_POWER_mulo (void);
+#if !defined(CONFIG_USER_ONLY)
+void do_POWER_rac (void);
+void do_POWER_rfsvc (void);
+#endif
+
+/* PowerPC 602 specific helper */
+#if !defined(CONFIG_USER_ONLY)
+void do_op_602_mfrom (void);
+#endif
+
+/* PowerPC 4xx specific helpers */
+void do_405_check_ov (void);
+void do_405_check_sat (void);
+#if !defined(CONFIG_USER_ONLY)
+void do_load_dcr (void);
+void do_store_dcr (void);
+void do_40x_rfci (void);
+void do_rfci (void);
+void do_rfdi (void);
+void do_rfmci (void);
+void do_4xx_tlbre_lo (void);
+void do_4xx_tlbre_hi (void);
+void do_4xx_tlbsx (void);
+void do_4xx_tlbsx_ (void);
+void do_4xx_tlbwe_lo (void);
+void do_4xx_tlbwe_hi (void);
+#endif
+
+/* PowerPC 440 specific helpers */
+void do_440_dlmzb (void);
+
+/* PowerPC 403 specific helpers */
+#if !defined(CONFIG_USER_ONLY)
+void do_load_403_pb (int num);
+void do_store_403_pb (int num);
+#endif
+
+#if defined(TARGET_PPCEMB)
+/* SPE extension helpers */
+void do_brinc (void);
+/* Fixed-point vector helpers */
+void do_evabs (void);
+void do_evaddw (void);
+void do_evcntlsw (void);
+void do_evcntlzw (void);
+void do_evneg (void);
+void do_evrlw (void);
+void do_evsel (void);
+void do_evrndw (void);
+void do_evslw (void);
+void do_evsrws (void);
+void do_evsrwu (void);
+void do_evsubfw (void);
+void do_evcmpeq (void);
+void do_evcmpgts (void);
+void do_evcmpgtu (void);
+void do_evcmplts (void);
+void do_evcmpltu (void);
+
+/* Single precision floating-point helpers */
+void do_efscmplt (void);
+void do_efscmpgt (void);
+void do_efscmpeq (void);
+void do_efscfsf (void);
+void do_efscfuf (void);
+void do_efsctsf (void);
+void do_efsctuf (void);
+
+void do_efscfsi (void);
+void do_efscfui (void);
+void do_efsctsi (void);
+void do_efsctui (void);
+void do_efsctsiz (void);
+void do_efsctuiz (void);
+
+/* Double precision floating-point helpers */
+void do_efdcmplt (void);
+void do_efdcmpgt (void);
+void do_efdcmpeq (void);
+void do_efdcfsf (void);
+void do_efdcfuf (void);
+void do_efdctsf (void);
+void do_efdctuf (void);
+
+void do_efdcfsi (void);
+void do_efdcfui (void);
+void do_efdctsi (void);
+void do_efdctui (void);
+void do_efdctsiz (void);
+void do_efdctuiz (void);
+
+void do_efdcfs (void);
+void do_efscfd (void);
+
+/* Floating-point vector helpers */
+void do_evfsabs (void);
+void do_evfsnabs (void);
+void do_evfsneg (void);
+void do_evfsadd (void);
+void do_evfssub (void);
+void do_evfsmul (void);
+void do_evfsdiv (void);
+void do_evfscmplt (void);
+void do_evfscmpgt (void);
+void do_evfscmpeq (void);
+void do_evfststlt (void);
+void do_evfststgt (void);
+void do_evfststeq (void);
+void do_evfscfsi (void);
+void do_evfscfui (void);
+void do_evfscfsf (void);
+void do_evfscfuf (void);
+void do_evfsctsf (void);
+void do_evfsctuf (void);
+void do_evfsctsi (void);
+void do_evfsctui (void);
+void do_evfsctsiz (void);
+void do_evfsctuiz (void);
+#endif /* defined(TARGET_PPCEMB) */
+
+/* Inlined helpers: used in micro-operation as well as helpers */
+/* Generic fixed-point helpers */
+static inline int _do_cntlzw (uint32_t val)
+{
+ int cnt = 0;
+ if (!(val & 0xFFFF0000UL)) {
+ cnt += 16;
+ val <<= 16;
+ }
+ if (!(val & 0xFF000000UL)) {
+ cnt += 8;
+ val <<= 8;
+ }
+ if (!(val & 0xF0000000UL)) {
+ cnt += 4;
+ val <<= 4;
+ }
+ if (!(val & 0xC0000000UL)) {
+ cnt += 2;
+ val <<= 2;
+ }
+ if (!(val & 0x80000000UL)) {
+ cnt++;
+ val <<= 1;
+ }
+ if (!(val & 0x80000000UL)) {
+ cnt++;
+ }
+ return cnt;
+}
+
+static inline int _do_cntlzd (uint64_t val)
+{
+ int cnt = 0;
+#if HOST_LONG_BITS == 64
+ if (!(val & 0xFFFFFFFF00000000ULL)) {
+ cnt += 32;
+ val <<= 32;
+ }
+ if (!(val & 0xFFFF000000000000ULL)) {
+ cnt += 16;
+ val <<= 16;
+ }
+ if (!(val & 0xFF00000000000000ULL)) {
+ cnt += 8;
+ val <<= 8;
+ }
+ if (!(val & 0xF000000000000000ULL)) {
+ cnt += 4;
+ val <<= 4;
+ }
+ if (!(val & 0xC000000000000000ULL)) {
+ cnt += 2;
+ val <<= 2;
+ }
+ if (!(val & 0x8000000000000000ULL)) {
+ cnt++;
+ val <<= 1;
+ }
+ if (!(val & 0x8000000000000000ULL)) {
+ cnt++;
+ }
+#else
+ /* Make it easier on 32 bits host machines */
+ if (!(val >> 32))
+ cnt = _do_cntlzw(val) + 32;
+ else
+ cnt = _do_cntlzw(val >> 32);
+#endif
+ return cnt;
+}
+
+#if defined(TARGET_PPCEMB)
+/* SPE extension */
+/* Single precision floating-point helpers */
+static inline uint32_t _do_efsabs (uint32_t val)
+{
+ return val & ~0x80000000;
+}
+static inline uint32_t _do_efsnabs (uint32_t val)
+{
+ return val | 0x80000000;
+}
+static inline uint32_t _do_efsneg (uint32_t val)
+{
+ return val ^ 0x80000000;
+}
+static inline uint32_t _do_efsadd (uint32_t op1, uint32_t op2)
+{
+ union {
+ uint32_t u;
+ float32 f;
+ } u1, u2;
+ u1.u = op1;
+ u2.u = op2;
+ u1.f = float32_add(u1.f, u2.f, &env->spe_status);
+ return u1.u;
+}
+static inline uint32_t _do_efssub (uint32_t op1, uint32_t op2)
+{
+ union {
+ uint32_t u;
+ float32 f;
+ } u1, u2;
+ u1.u = op1;
+ u2.u = op2;
+ u1.f = float32_sub(u1.f, u2.f, &env->spe_status);
+ return u1.u;
+}
+static inline uint32_t _do_efsmul (uint32_t op1, uint32_t op2)
+{
+ union {
+ uint32_t u;
+ float32 f;
+ } u1, u2;
+ u1.u = op1;
+ u2.u = op2;
+ u1.f = float32_mul(u1.f, u2.f, &env->spe_status);
+ return u1.u;
+}
+static inline uint32_t _do_efsdiv (uint32_t op1, uint32_t op2)
+{
+ union {
+ uint32_t u;
+ float32 f;
+ } u1, u2;
+ u1.u = op1;
+ u2.u = op2;
+ u1.f = float32_div(u1.f, u2.f, &env->spe_status);
+ return u1.u;
+}
+
+static inline int _do_efststlt (uint32_t op1, uint32_t op2)
+{
+ union {
+ uint32_t u;
+ float32 f;
+ } u1, u2;
+ u1.u = op1;
+ u2.u = op2;
+ return float32_lt(u1.f, u2.f, &env->spe_status) ? 1 : 0;
+}
+static inline int _do_efststgt (uint32_t op1, uint32_t op2)
+{
+ union {
+ uint32_t u;
+ float32 f;
+ } u1, u2;
+ u1.u = op1;
+ u2.u = op2;
+ return float32_le(u1.f, u2.f, &env->spe_status) ? 0 : 1;
+}
+static inline int _do_efststeq (uint32_t op1, uint32_t op2)
+{
+ union {
+ uint32_t u;
+ float32 f;
+ } u1, u2;
+ u1.u = op1;
+ u2.u = op2;
+ return float32_eq(u1.f, u2.f, &env->spe_status) ? 1 : 0;
+}
+/* Double precision floating-point helpers */
+static inline int _do_efdtstlt (uint64_t op1, uint64_t op2)
+{
+ union {
+ uint64_t u;
+ float64 f;
+ } u1, u2;
+ u1.u = op1;
+ u2.u = op2;
+ return float64_lt(u1.f, u2.f, &env->spe_status) ? 1 : 0;
+}
+static inline int _do_efdtstgt (uint64_t op1, uint64_t op2)
+{
+ union {
+ uint64_t u;
+ float64 f;
+ } u1, u2;
+ u1.u = op1;
+ u2.u = op2;
+ return float64_le(u1.f, u2.f, &env->spe_status) ? 0 : 1;
+}
+static inline int _do_efdtsteq (uint64_t op1, uint64_t op2)
+{
+ union {
+ uint64_t u;
+ float64 f;
+ } u1, u2;
+ u1.u = op1;
+ u2.u = op2;
+ return float64_eq(u1.f, u2.f, &env->spe_status) ? 1 : 0;
+}
+#endif /* defined(TARGET_PPCEMB) */
+#endif
Modified: trunk/src/host/qemu-neo1973/target-ppc/op_helper_mem.h
===================================================================
--- trunk/src/host/qemu-neo1973/target-ppc/op_helper_mem.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/target-ppc/op_helper_mem.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -1,3 +1,103 @@
+/*
+ * PowerPC emulation micro-operations helpers for qemu.
+ *
+ * Copyright (c) 2003-2007 Jocelyn Mayer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/* Multiple word / string load and store */
+static inline target_ulong glue(ld32r, MEMSUFFIX) (target_ulong EA)
+{
+ uint32_t tmp = glue(ldl, MEMSUFFIX)(EA);
+ return ((tmp & 0xFF000000UL) >> 24) | ((tmp & 0x00FF0000UL) >> 8) |
+ ((tmp & 0x0000FF00UL) << 8) | ((tmp & 0x000000FFUL) << 24);
+}
+
+static inline void glue(st32r, MEMSUFFIX) (target_ulong EA, target_ulong data)
+{
+ uint32_t tmp =
+ ((data & 0xFF000000UL) >> 24) | ((data & 0x00FF0000UL) >> 8) |
+ ((data & 0x0000FF00UL) << 8) | ((data & 0x000000FFUL) << 24);
+ glue(stl, MEMSUFFIX)(EA, tmp);
+}
+
+void glue(do_lmw, MEMSUFFIX) (int dst)
+{
+ for (; dst < 32; dst++, T0 += 4) {
+ ugpr(dst) = glue(ldl, MEMSUFFIX)((uint32_t)T0);
+ }
+}
+
+#if defined(TARGET_PPC64)
+void glue(do_lmw_64, MEMSUFFIX) (int dst)
+{
+ for (; dst < 32; dst++, T0 += 4) {
+ ugpr(dst) = glue(ldl, MEMSUFFIX)((uint64_t)T0);
+ }
+}
+#endif
+
+void glue(do_stmw, MEMSUFFIX) (int src)
+{
+ for (; src < 32; src++, T0 += 4) {
+ glue(stl, MEMSUFFIX)((uint32_t)T0, ugpr(src));
+ }
+}
+
+#if defined(TARGET_PPC64)
+void glue(do_stmw_64, MEMSUFFIX) (int src)
+{
+ for (; src < 32; src++, T0 += 4) {
+ glue(stl, MEMSUFFIX)((uint64_t)T0, ugpr(src));
+ }
+}
+#endif
+
+void glue(do_lmw_le, MEMSUFFIX) (int dst)
+{
+ for (; dst < 32; dst++, T0 += 4) {
+ ugpr(dst) = glue(ld32r, MEMSUFFIX)((uint32_t)T0);
+ }
+}
+
+#if defined(TARGET_PPC64)
+void glue(do_lmw_le_64, MEMSUFFIX) (int dst)
+{
+ for (; dst < 32; dst++, T0 += 4) {
+ ugpr(dst) = glue(ld32r, MEMSUFFIX)((uint64_t)T0);
+ }
+}
+#endif
+
+void glue(do_stmw_le, MEMSUFFIX) (int src)
+{
+ for (; src < 32; src++, T0 += 4) {
+ glue(st32r, MEMSUFFIX)((uint32_t)T0, ugpr(src));
+ }
+}
+
+#if defined(TARGET_PPC64)
+void glue(do_stmw_le_64, MEMSUFFIX) (int src)
+{
+ for (; src < 32; src++, T0 += 4) {
+ glue(st32r, MEMSUFFIX)((uint64_t)T0, ugpr(src));
+ }
+}
+#endif
+
void glue(do_lsw, MEMSUFFIX) (int dst)
{
uint32_t tmp;
@@ -3,44 +103,70 @@
int sh;
-#if 0
- if (loglevel > 0) {
- fprintf(logfile, "%s: addr=0x%08x count=%d reg=%d\n",
- __func__, T0, T1, dst);
+ for (; T1 > 3; T1 -= 4, T0 += 4) {
+ ugpr(dst++) = glue(ldl, MEMSUFFIX)((uint32_t)T0);
+ if (unlikely(dst == 32))
+ dst = 0;
}
-#endif
+ if (unlikely(T1 != 0)) {
+ tmp = 0;
+ for (sh = 24; T1 > 0; T1--, T0++, sh -= 8) {
+ tmp |= glue(ldub, MEMSUFFIX)((uint32_t)T0) << sh;
+ }
+ ugpr(dst) = tmp;
+ }
+}
+
+#if defined(TARGET_PPC64)
+void glue(do_lsw_64, MEMSUFFIX) (int dst)
+{
+ uint32_t tmp;
+ int sh;
+
for (; T1 > 3; T1 -= 4, T0 += 4) {
- ugpr(dst++) = glue(ldl, MEMSUFFIX)(T0);
- if (dst == 32)
+ ugpr(dst++) = glue(ldl, MEMSUFFIX)((uint64_t)T0);
+ if (unlikely(dst == 32))
dst = 0;
}
- if (T1 > 0) {
+ if (unlikely(T1 != 0)) {
tmp = 0;
for (sh = 24; T1 > 0; T1--, T0++, sh -= 8) {
- tmp |= glue(ldub, MEMSUFFIX)(T0) << sh;
+ tmp |= glue(ldub, MEMSUFFIX)((uint64_t)T0) << sh;
}
ugpr(dst) = tmp;
}
}
+#endif
void glue(do_stsw, MEMSUFFIX) (int src)
{
int sh;
-#if 0
- if (loglevel > 0) {
- fprintf(logfile, "%s: addr=0x%08x count=%d reg=%d\n",
- __func__, T0, T1, src);
+ for (; T1 > 3; T1 -= 4, T0 += 4) {
+ glue(stl, MEMSUFFIX)((uint32_t)T0, ugpr(src++));
+ if (unlikely(src == 32))
+ src = 0;
}
-#endif
+ if (unlikely(T1 != 0)) {
+ for (sh = 24; T1 > 0; T1--, T0++, sh -= 8)
+ glue(stb, MEMSUFFIX)((uint32_t)T0, (ugpr(src) >> sh) & 0xFF);
+ }
+}
+
+#if defined(TARGET_PPC64)
+void glue(do_stsw_64, MEMSUFFIX) (int src)
+{
+ int sh;
+
for (; T1 > 3; T1 -= 4, T0 += 4) {
- glue(stl, MEMSUFFIX)(T0, ugpr(src++));
- if (src == 32)
+ glue(stl, MEMSUFFIX)((uint64_t)T0, ugpr(src++));
+ if (unlikely(src == 32))
src = 0;
}
- if (T1 > 0) {
+ if (unlikely(T1 != 0)) {
for (sh = 24; T1 > 0; T1--, T0++, sh -= 8)
- glue(stb, MEMSUFFIX)(T0, (ugpr(src) >> sh) & 0xFF);
+ glue(stb, MEMSUFFIX)((uint64_t)T0, (ugpr(src) >> sh) & 0xFF);
}
}
+#endif
void glue(do_lsw_le, MEMSUFFIX) (int dst)
@@ -49,52 +175,191 @@
uint32_t tmp;
int sh;
-#if 0
- if (loglevel > 0) {
- fprintf(logfile, "%s: addr=0x%08x count=%d reg=%d\n",
- __func__, T0, T1, dst);
- }
-#endif
for (; T1 > 3; T1 -= 4, T0 += 4) {
- tmp = glue(ldl, MEMSUFFIX)(T0);
- ugpr(dst++) = ((tmp & 0xFF000000) >> 24) | ((tmp & 0x00FF0000) >> 8) |
- ((tmp & 0x0000FF00) << 8) | ((tmp & 0x000000FF) << 24);
- if (dst == 32)
+ ugpr(dst++) = glue(ld32r, MEMSUFFIX)((uint32_t)T0);
+ if (unlikely(dst == 32))
dst = 0;
}
- if (T1 > 0) {
+ if (unlikely(T1 != 0)) {
tmp = 0;
for (sh = 0; T1 > 0; T1--, T0++, sh += 8) {
- tmp |= glue(ldub, MEMSUFFIX)(T0) << sh;
+ tmp |= glue(ldub, MEMSUFFIX)((uint32_t)T0) << sh;
}
ugpr(dst) = tmp;
}
}
-void glue(do_stsw_le, MEMSUFFIX) (int src)
+#if defined(TARGET_PPC64)
+void glue(do_lsw_le_64, MEMSUFFIX) (int dst)
{
uint32_t tmp;
int sh;
-#if 0
- if (loglevel > 0) {
- fprintf(logfile, "%s: addr=0x%08x count=%d reg=%d\n",
- __func__, T0, T1, src);
+ for (; T1 > 3; T1 -= 4, T0 += 4) {
+ ugpr(dst++) = glue(ld32r, MEMSUFFIX)((uint64_t)T0);
+ if (unlikely(dst == 32))
+ dst = 0;
}
+ if (unlikely(T1 != 0)) {
+ tmp = 0;
+ for (sh = 0; T1 > 0; T1--, T0++, sh += 8) {
+ tmp |= glue(ldub, MEMSUFFIX)((uint64_t)T0) << sh;
+ }
+ ugpr(dst) = tmp;
+ }
+}
#endif
+
+void glue(do_stsw_le, MEMSUFFIX) (int src)
+{
+ int sh;
+
for (; T1 > 3; T1 -= 4, T0 += 4) {
- tmp = ((ugpr(src++) & 0xFF000000) >> 24);
- tmp |= ((ugpr(src++) & 0x00FF0000) >> 8);
- tmp |= ((ugpr(src++) & 0x0000FF00) << 8);
- tmp |= ((ugpr(src++) & 0x000000FF) << 24);
- glue(stl, MEMSUFFIX)(T0, tmp);
- if (src == 32)
+ glue(st32r, MEMSUFFIX)((uint32_t)T0, ugpr(src++));
+ if (unlikely(src == 32))
src = 0;
}
- if (T1 > 0) {
+ if (unlikely(T1 != 0)) {
for (sh = 0; T1 > 0; T1--, T0++, sh += 8)
- glue(stb, MEMSUFFIX)(T0, (ugpr(src) >> sh) & 0xFF);
+ glue(stb, MEMSUFFIX)((uint32_t)T0, (ugpr(src) >> sh) & 0xFF);
}
}
+#if defined(TARGET_PPC64)
+void glue(do_stsw_le_64, MEMSUFFIX) (int src)
+{
+ int sh;
+
+ for (; T1 > 3; T1 -= 4, T0 += 4) {
+ glue(st32r, MEMSUFFIX)((uint64_t)T0, ugpr(src++));
+ if (unlikely(src == 32))
+ src = 0;
+ }
+ if (unlikely(T1 != 0)) {
+ for (sh = 0; T1 > 0; T1--, T0++, sh += 8)
+ glue(stb, MEMSUFFIX)((uint64_t)T0, (ugpr(src) >> sh) & 0xFF);
+ }
+}
+#endif
+
+/* Instruction cache invalidation helper */
+void glue(do_icbi, MEMSUFFIX) (void)
+{
+ uint32_t tmp;
+ /* Invalidate one cache line :
+ * PowerPC specification says this is to be treated like a load
+ * (not a fetch) by the MMU. To be sure it will be so,
+ * do the load "by hand".
+ */
+ tmp = glue(ldl, MEMSUFFIX)((uint32_t)T0);
+ T0 &= ~(ICACHE_LINE_SIZE - 1);
+ tb_invalidate_page_range((uint32_t)T0, (uint32_t)(T0 + ICACHE_LINE_SIZE));
+}
+
+#if defined(TARGET_PPC64)
+void glue(do_icbi_64, MEMSUFFIX) (void)
+{
+ uint64_t tmp;
+ /* Invalidate one cache line :
+ * PowerPC specification says this is to be treated like a load
+ * (not a fetch) by the MMU. To be sure it will be so,
+ * do the load "by hand".
+ */
+ tmp = glue(ldq, MEMSUFFIX)((uint64_t)T0);
+ T0 &= ~(ICACHE_LINE_SIZE - 1);
+ tb_invalidate_page_range((uint64_t)T0, (uint64_t)(T0 + ICACHE_LINE_SIZE));
+}
+#endif
+
+/* PPC 601 specific instructions (POWER bridge) */
+// XXX: to be tested
+void glue(do_POWER_lscbx, MEMSUFFIX) (int dest, int ra, int rb)
+{
+ int i, c, d, reg;
+
+ d = 24;
+ reg = dest;
+ for (i = 0; i < T1; i++) {
+ c = glue(ldub, MEMSUFFIX)((uint32_t)T0++);
+ /* ra (if not 0) and rb are never modified */
+ if (likely(reg != rb && (ra == 0 || reg != ra))) {
+ ugpr(reg) = (ugpr(reg) & ~(0xFF << d)) | (c << d);
+ }
+ if (unlikely(c == T2))
+ break;
+ if (likely(d != 0)) {
+ d -= 8;
+ } else {
+ d = 24;
+ reg++;
+ reg = reg & 0x1F;
+ }
+ }
+ T0 = i;
+}
+
+/* XXX: TAGs are not managed */
+void glue(do_POWER2_lfq, MEMSUFFIX) (void)
+{
+ FT0 = glue(ldfq, MEMSUFFIX)((uint32_t)T0);
+ FT1 = glue(ldfq, MEMSUFFIX)((uint32_t)(T0 + 4));
+}
+
+static inline double glue(ldfqr, MEMSUFFIX) (target_ulong EA)
+{
+ union {
+ double d;
+ uint64_t u;
+ } u;
+
+ u.d = glue(ldfq, MEMSUFFIX)(EA);
+ u.u = ((u.u & 0xFF00000000000000ULL) >> 56) |
+ ((u.u & 0x00FF000000000000ULL) >> 40) |
+ ((u.u & 0x0000FF0000000000ULL) >> 24) |
+ ((u.u & 0x000000FF00000000ULL) >> 8) |
+ ((u.u & 0x00000000FF000000ULL) << 8) |
+ ((u.u & 0x0000000000FF0000ULL) << 24) |
+ ((u.u & 0x000000000000FF00ULL) << 40) |
+ ((u.u & 0x00000000000000FFULL) << 56);
+
+ return u.d;
+}
+
+void glue(do_POWER2_lfq_le, MEMSUFFIX) (void)
+{
+ FT0 = glue(ldfqr, MEMSUFFIX)((uint32_t)(T0 + 4));
+ FT1 = glue(ldfqr, MEMSUFFIX)((uint32_t)T0);
+}
+
+void glue(do_POWER2_stfq, MEMSUFFIX) (void)
+{
+ glue(stfq, MEMSUFFIX)((uint32_t)T0, FT0);
+ glue(stfq, MEMSUFFIX)((uint32_t)(T0 + 4), FT1);
+}
+
+static inline void glue(stfqr, MEMSUFFIX) (target_ulong EA, double d)
+{
+ union {
+ double d;
+ uint64_t u;
+ } u;
+
+ u.d = d;
+ u.u = ((u.u & 0xFF00000000000000ULL) >> 56) |
+ ((u.u & 0x00FF000000000000ULL) >> 40) |
+ ((u.u & 0x0000FF0000000000ULL) >> 24) |
+ ((u.u & 0x000000FF00000000ULL) >> 8) |
+ ((u.u & 0x00000000FF000000ULL) << 8) |
+ ((u.u & 0x0000000000FF0000ULL) << 24) |
+ ((u.u & 0x000000000000FF00ULL) << 40) |
+ ((u.u & 0x00000000000000FFULL) << 56);
+ glue(stfq, MEMSUFFIX)(EA, u.d);
+}
+
+void glue(do_POWER2_stfq_le, MEMSUFFIX) (void)
+{
+ glue(stfqr, MEMSUFFIX)((uint32_t)(T0 + 4), FT0);
+ glue(stfqr, MEMSUFFIX)((uint32_t)T0, FT1);
+}
+
#undef MEMSUFFIX
Modified: trunk/src/host/qemu-neo1973/target-ppc/op_mem.h
===================================================================
--- trunk/src/host/qemu-neo1973/target-ppc/op_mem.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/target-ppc/op_mem.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -1,6 +1,22 @@
-/* External helpers */
-void glue(do_lsw, MEMSUFFIX) (int dst);
-void glue(do_stsw, MEMSUFFIX) (int src);
+/*
+ * PowerPC emulation micro-operations for qemu.
+ *
+ * Copyright (c) 2003-2007 Jocelyn Mayer
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
static inline uint16_t glue(ld16r, MEMSUFFIX) (target_ulong EA)
{
@@ -11,7 +27,7 @@
static inline int32_t glue(ld16rs, MEMSUFFIX) (target_ulong EA)
{
int16_t tmp = glue(lduw, MEMSUFFIX)(EA);
- return ((tmp & 0xFF00) >> 8) | ((tmp & 0x00FF) << 8);
+ return (int16_t)((tmp & 0xFF00) >> 8) | ((tmp & 0x00FF) << 8);
}
static inline uint32_t glue(ld32r, MEMSUFFIX) (target_ulong EA)
@@ -21,6 +37,35 @@
((tmp & 0x0000FF00) << 8) | ((tmp & 0x000000FF) << 24);
}
+#if defined(TARGET_PPC64) || defined(TARGET_PPCEMB)
+static inline uint64_t glue(ld64r, MEMSUFFIX) (target_ulong EA)
+{
+ uint64_t tmp = glue(ldq, MEMSUFFIX)(EA);
+ return ((tmp & 0xFF00000000000000ULL) >> 56) |
+ ((tmp & 0x00FF000000000000ULL) >> 40) |
+ ((tmp & 0x0000FF0000000000ULL) >> 24) |
+ ((tmp & 0x000000FF00000000ULL) >> 8) |
+ ((tmp & 0x00000000FF000000ULL) << 8) |
+ ((tmp & 0x0000000000FF0000ULL) << 24) |
+ ((tmp & 0x000000000000FF00ULL) << 40) |
+ ((tmp & 0x00000000000000FFULL) << 54);
+}
+#endif
+
+#if defined(TARGET_PPC64)
+static inline int64_t glue(ldsl, MEMSUFFIX) (target_ulong EA)
+{
+ return (int32_t)glue(ldl, MEMSUFFIX)(EA);
+}
+
+static inline int64_t glue(ld32rs, MEMSUFFIX) (target_ulong EA)
+{
+ uint32_t tmp = glue(ldl, MEMSUFFIX)(EA);
+ return (int32_t)((tmp & 0xFF000000) >> 24) | ((tmp & 0x00FF0000) >> 8) |
+ ((tmp & 0x0000FF00) << 8) | ((tmp & 0x000000FF) << 24);
+}
+#endif
+
static inline void glue(st16r, MEMSUFFIX) (target_ulong EA, uint16_t data)
{
uint16_t tmp = ((data & 0xFF00) >> 8) | ((data & 0x00FF) << 8);
@@ -34,158 +79,328 @@
glue(stl, MEMSUFFIX)(EA, tmp);
}
+#if defined(TARGET_PPC64) || defined(TARGET_PPCEMB)
+static inline void glue(st64r, MEMSUFFIX) (target_ulong EA, uint64_t data)
+{
+ uint64_t tmp = ((data & 0xFF00000000000000ULL) >> 56) |
+ ((data & 0x00FF000000000000ULL) >> 40) |
+ ((data & 0x0000FF0000000000ULL) >> 24) |
+ ((data & 0x000000FF00000000ULL) >> 8) |
+ ((data & 0x00000000FF000000ULL) << 8) |
+ ((data & 0x0000000000FF0000ULL) << 24) |
+ ((data & 0x000000000000FF00ULL) << 40) |
+ ((data & 0x00000000000000FFULL) << 56);
+ glue(stq, MEMSUFFIX)(EA, tmp);
+}
+#endif
+
/*** Integer load ***/
#define PPC_LD_OP(name, op) \
-PPC_OP(glue(glue(l, name), MEMSUFFIX)) \
+void OPPROTO glue(glue(op_l, name), MEMSUFFIX) (void) \
{ \
- T1 = glue(op, MEMSUFFIX)(T0); \
+ T1 = glue(op, MEMSUFFIX)((uint32_t)T0); \
RETURN(); \
}
+#if defined(TARGET_PPC64)
+#define PPC_LD_OP_64(name, op) \
+void OPPROTO glue(glue(glue(op_l, name), _64), MEMSUFFIX) (void) \
+{ \
+ T1 = glue(op, MEMSUFFIX)((uint64_t)T0); \
+ RETURN(); \
+}
+#endif
+
#define PPC_ST_OP(name, op) \
-PPC_OP(glue(glue(st, name), MEMSUFFIX)) \
+void OPPROTO glue(glue(op_st, name), MEMSUFFIX) (void) \
{ \
- glue(op, MEMSUFFIX)(T0, T1); \
+ glue(op, MEMSUFFIX)((uint32_t)T0, T1); \
RETURN(); \
}
+#if defined(TARGET_PPC64)
+#define PPC_ST_OP_64(name, op) \
+void OPPROTO glue(glue(glue(op_st, name), _64), MEMSUFFIX) (void) \
+{ \
+ glue(op, MEMSUFFIX)((uint64_t)T0, T1); \
+ RETURN(); \
+}
+#endif
+
PPC_LD_OP(bz, ldub);
PPC_LD_OP(ha, ldsw);
PPC_LD_OP(hz, lduw);
PPC_LD_OP(wz, ldl);
+#if defined(TARGET_PPC64)
+PPC_LD_OP(d, ldq);
+PPC_LD_OP(wa, ldsl);
+PPC_LD_OP_64(d, ldq);
+PPC_LD_OP_64(wa, ldsl);
+PPC_LD_OP_64(bz, ldub);
+PPC_LD_OP_64(ha, ldsw);
+PPC_LD_OP_64(hz, lduw);
+PPC_LD_OP_64(wz, ldl);
+#endif
PPC_LD_OP(ha_le, ld16rs);
PPC_LD_OP(hz_le, ld16r);
PPC_LD_OP(wz_le, ld32r);
+#if defined(TARGET_PPC64)
+PPC_LD_OP(d_le, ld64r);
+PPC_LD_OP(wa_le, ld32rs);
+PPC_LD_OP_64(d_le, ld64r);
+PPC_LD_OP_64(wa_le, ld32rs);
+PPC_LD_OP_64(ha_le, ld16rs);
+PPC_LD_OP_64(hz_le, ld16r);
+PPC_LD_OP_64(wz_le, ld32r);
+#endif
/*** Integer store ***/
PPC_ST_OP(b, stb);
PPC_ST_OP(h, stw);
PPC_ST_OP(w, stl);
+#if defined(TARGET_PPC64)
+PPC_ST_OP(d, stq);
+PPC_ST_OP_64(d, stq);
+PPC_ST_OP_64(b, stb);
+PPC_ST_OP_64(h, stw);
+PPC_ST_OP_64(w, stl);
+#endif
PPC_ST_OP(h_le, st16r);
PPC_ST_OP(w_le, st32r);
+#if defined(TARGET_PPC64)
+PPC_ST_OP(d_le, st64r);
+PPC_ST_OP_64(d_le, st64r);
+PPC_ST_OP_64(h_le, st16r);
+PPC_ST_OP_64(w_le, st32r);
+#endif
/*** Integer load and store with byte reverse ***/
PPC_LD_OP(hbr, ld16r);
PPC_LD_OP(wbr, ld32r);
PPC_ST_OP(hbr, st16r);
PPC_ST_OP(wbr, st32r);
+#if defined(TARGET_PPC64)
+PPC_LD_OP_64(hbr, ld16r);
+PPC_LD_OP_64(wbr, ld32r);
+PPC_ST_OP_64(hbr, st16r);
+PPC_ST_OP_64(wbr, st32r);
+#endif
PPC_LD_OP(hbr_le, lduw);
PPC_LD_OP(wbr_le, ldl);
PPC_ST_OP(hbr_le, stw);
PPC_ST_OP(wbr_le, stl);
+#if defined(TARGET_PPC64)
+PPC_LD_OP_64(hbr_le, lduw);
+PPC_LD_OP_64(wbr_le, ldl);
+PPC_ST_OP_64(hbr_le, stw);
+PPC_ST_OP_64(wbr_le, stl);
+#endif
/*** Integer load and store multiple ***/
-PPC_OP(glue(lmw, MEMSUFFIX))
+void OPPROTO glue(op_lmw, MEMSUFFIX) (void)
{
- int dst = PARAM(1);
+ glue(do_lmw, MEMSUFFIX)(PARAM1);
+ RETURN();
+}
- for (; dst < 32; dst++, T0 += 4) {
- ugpr(dst) = glue(ldl, MEMSUFFIX)(T0);
- }
+#if defined(TARGET_PPC64)
+void OPPROTO glue(op_lmw_64, MEMSUFFIX) (void)
+{
+ glue(do_lmw_64, MEMSUFFIX)(PARAM1);
RETURN();
}
+#endif
-PPC_OP(glue(stmw, MEMSUFFIX))
+void OPPROTO glue(op_lmw_le, MEMSUFFIX) (void)
{
- int src = PARAM(1);
+ glue(do_lmw_le, MEMSUFFIX)(PARAM1);
+ RETURN();
+}
- for (; src < 32; src++, T0 += 4) {
- glue(stl, MEMSUFFIX)(T0, ugpr(src));
- }
+#if defined(TARGET_PPC64)
+void OPPROTO glue(op_lmw_le_64, MEMSUFFIX) (void)
+{
+ glue(do_lmw_le_64, MEMSUFFIX)(PARAM1);
RETURN();
}
+#endif
-PPC_OP(glue(lmw_le, MEMSUFFIX))
+void OPPROTO glue(op_stmw, MEMSUFFIX) (void)
{
- int dst = PARAM(1);
+ glue(do_stmw, MEMSUFFIX)(PARAM1);
+ RETURN();
+}
- for (; dst < 32; dst++, T0 += 4) {
- ugpr(dst) = glue(ld32r, MEMSUFFIX)(T0);
- }
+#if defined(TARGET_PPC64)
+void OPPROTO glue(op_stmw_64, MEMSUFFIX) (void)
+{
+ glue(do_stmw_64, MEMSUFFIX)(PARAM1);
RETURN();
}
+#endif
-PPC_OP(glue(stmw_le, MEMSUFFIX))
+void OPPROTO glue(op_stmw_le, MEMSUFFIX) (void)
{
- int src = PARAM(1);
+ glue(do_stmw_le, MEMSUFFIX)(PARAM1);
+ RETURN();
+}
- for (; src < 32; src++, T0 += 4) {
- glue(st32r, MEMSUFFIX)(T0, ugpr(src));
- }
+#if defined(TARGET_PPC64)
+void OPPROTO glue(op_stmw_le_64, MEMSUFFIX) (void)
+{
+ glue(do_stmw_le_64, MEMSUFFIX)(PARAM1);
RETURN();
}
+#endif
/*** Integer load and store strings ***/
-PPC_OP(glue(lswi, MEMSUFFIX))
+void OPPROTO glue(op_lswi, MEMSUFFIX) (void)
{
- glue(do_lsw, MEMSUFFIX)(PARAM(1));
+ glue(do_lsw, MEMSUFFIX)(PARAM1);
RETURN();
}
-void glue(do_lsw_le, MEMSUFFIX) (int dst);
-PPC_OP(glue(lswi_le, MEMSUFFIX))
+#if defined(TARGET_PPC64)
+void OPPROTO glue(op_lswi_64, MEMSUFFIX) (void)
{
- glue(do_lsw_le, MEMSUFFIX)(PARAM(1));
+ glue(do_lsw_64, MEMSUFFIX)(PARAM1);
RETURN();
}
+#endif
+void OPPROTO glue(op_lswi_le, MEMSUFFIX) (void)
+{
+ glue(do_lsw_le, MEMSUFFIX)(PARAM1);
+ RETURN();
+}
+
+#if defined(TARGET_PPC64)
+void OPPROTO glue(op_lswi_le_64, MEMSUFFIX) (void)
+{
+ glue(do_lsw_le_64, MEMSUFFIX)(PARAM1);
+ RETURN();
+}
+#endif
+
/* PPC32 specification says we must generate an exception if
* rA is in the range of registers to be loaded.
* In an other hand, IBM says this is valid, but rA won't be loaded.
* For now, I'll follow the spec...
*/
-PPC_OP(glue(lswx, MEMSUFFIX))
+void OPPROTO glue(op_lswx, MEMSUFFIX) (void)
{
- if (T1 > 0) {
- if ((PARAM(1) < PARAM(2) && (PARAM(1) + T1) > PARAM(2)) ||
- (PARAM(1) < PARAM(3) && (PARAM(1) + T1) > PARAM(3))) {
+ /* Note: T1 comes from xer_bc then no cast is needed */
+ if (likely(T1 != 0)) {
+ if (unlikely((PARAM1 < PARAM2 && (PARAM1 + T1) > PARAM2) ||
+ (PARAM1 < PARAM3 && (PARAM1 + T1) > PARAM3))) {
do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX);
} else {
- glue(do_lsw, MEMSUFFIX)(PARAM(1));
+ glue(do_lsw, MEMSUFFIX)(PARAM1);
}
}
RETURN();
}
-PPC_OP(glue(lswx_le, MEMSUFFIX))
+#if defined(TARGET_PPC64)
+void OPPROTO glue(op_lswx_64, MEMSUFFIX) (void)
{
- if (T1 > 0) {
- if ((PARAM(1) < PARAM(2) && (PARAM(1) + T1) > PARAM(2)) ||
- (PARAM(1) < PARAM(3) && (PARAM(1) + T1) > PARAM(3))) {
+ /* Note: T1 comes from xer_bc then no cast is needed */
+ if (likely(T1 != 0)) {
+ if (unlikely((PARAM1 < PARAM2 && (PARAM1 + T1) > PARAM2) ||
+ (PARAM1 < PARAM3 && (PARAM1 + T1) > PARAM3))) {
do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX);
} else {
- glue(do_lsw_le, MEMSUFFIX)(PARAM(1));
+ glue(do_lsw_64, MEMSUFFIX)(PARAM1);
}
}
RETURN();
}
+#endif
-PPC_OP(glue(stsw, MEMSUFFIX))
+void OPPROTO glue(op_lswx_le, MEMSUFFIX) (void)
{
- glue(do_stsw, MEMSUFFIX)(PARAM(1));
+ /* Note: T1 comes from xer_bc then no cast is needed */
+ if (likely(T1 != 0)) {
+ if (unlikely((PARAM1 < PARAM2 && (PARAM1 + T1) > PARAM2) ||
+ (PARAM1 < PARAM3 && (PARAM1 + T1) > PARAM3))) {
+ do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX);
+ } else {
+ glue(do_lsw_le, MEMSUFFIX)(PARAM1);
+ }
+ }
RETURN();
}
-void glue(do_stsw_le, MEMSUFFIX) (int src);
-PPC_OP(glue(stsw_le, MEMSUFFIX))
+#if defined(TARGET_PPC64)
+void OPPROTO glue(op_lswx_le_64, MEMSUFFIX) (void)
{
- glue(do_stsw_le, MEMSUFFIX)(PARAM(1));
+ /* Note: T1 comes from xer_bc then no cast is needed */
+ if (likely(T1 != 0)) {
+ if (unlikely((PARAM1 < PARAM2 && (PARAM1 + T1) > PARAM2) ||
+ (PARAM1 < PARAM3 && (PARAM1 + T1) > PARAM3))) {
+ do_raise_exception_err(EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX);
+ } else {
+ glue(do_lsw_le_64, MEMSUFFIX)(PARAM1);
+ }
+ }
RETURN();
}
+#endif
+void OPPROTO glue(op_stsw, MEMSUFFIX) (void)
+{
+ glue(do_stsw, MEMSUFFIX)(PARAM1);
+ RETURN();
+}
+
+#if defined(TARGET_PPC64)
+void OPPROTO glue(op_stsw_64, MEMSUFFIX) (void)
+{
+ glue(do_stsw_64, MEMSUFFIX)(PARAM1);
+ RETURN();
+}
+#endif
+
+void OPPROTO glue(op_stsw_le, MEMSUFFIX) (void)
+{
+ glue(do_stsw_le, MEMSUFFIX)(PARAM1);
+ RETURN();
+}
+
+#if defined(TARGET_PPC64)
+void OPPROTO glue(op_stsw_le_64, MEMSUFFIX) (void)
+{
+ glue(do_stsw_le_64, MEMSUFFIX)(PARAM1);
+ RETURN();
+}
+#endif
+
/*** Floating-point store ***/
#define PPC_STF_OP(name, op) \
-PPC_OP(glue(glue(st, name), MEMSUFFIX)) \
+void OPPROTO glue(glue(op_st, name), MEMSUFFIX) (void) \
{ \
- glue(op, MEMSUFFIX)(T0, FT1); \
+ glue(op, MEMSUFFIX)((uint32_t)T0, FT0); \
RETURN(); \
}
+#if defined(TARGET_PPC64)
+#define PPC_STF_OP_64(name, op) \
+void OPPROTO glue(glue(glue(op_st, name), _64), MEMSUFFIX) (void) \
+{ \
+ glue(op, MEMSUFFIX)((uint64_t)T0, FT0); \
+ RETURN(); \
+}
+#endif
+
PPC_STF_OP(fd, stfq);
PPC_STF_OP(fs, stfl);
+#if defined(TARGET_PPC64)
+PPC_STF_OP_64(fd, stfq);
+PPC_STF_OP_64(fs, stfl);
+#endif
static inline void glue(stfqr, MEMSUFFIX) (target_ulong EA, double d)
{
@@ -223,17 +438,34 @@
PPC_STF_OP(fd_le, stfqr);
PPC_STF_OP(fs_le, stflr);
+#if defined(TARGET_PPC64)
+PPC_STF_OP_64(fd_le, stfqr);
+PPC_STF_OP_64(fs_le, stflr);
+#endif
/*** Floating-point load ***/
#define PPC_LDF_OP(name, op) \
-PPC_OP(glue(glue(l, name), MEMSUFFIX)) \
+void OPPROTO glue(glue(op_l, name), MEMSUFFIX) (void) \
{ \
- FT1 = glue(op, MEMSUFFIX)(T0); \
+ FT0 = glue(op, MEMSUFFIX)((uint32_t)T0); \
RETURN(); \
}
+#if defined(TARGET_PPC64)
+#define PPC_LDF_OP_64(name, op) \
+void OPPROTO glue(glue(glue(op_l, name), _64), MEMSUFFIX) (void) \
+{ \
+ FT0 = glue(op, MEMSUFFIX)((uint64_t)T0); \
+ RETURN(); \
+}
+#endif
+
PPC_LDF_OP(fd, ldfq);
PPC_LDF_OP(fs, ldfl);
+#if defined(TARGET_PPC64)
+PPC_LDF_OP_64(fd, ldfq);
+PPC_LDF_OP_64(fs, ldfl);
+#endif
static inline double glue(ldfqr, MEMSUFFIX) (target_ulong EA)
{
@@ -273,99 +505,652 @@
PPC_LDF_OP(fd_le, ldfqr);
PPC_LDF_OP(fs_le, ldflr);
+#if defined(TARGET_PPC64)
+PPC_LDF_OP_64(fd_le, ldfqr);
+PPC_LDF_OP_64(fs_le, ldflr);
+#endif
/* Load and set reservation */
-PPC_OP(glue(lwarx, MEMSUFFIX))
+void OPPROTO glue(op_lwarx, MEMSUFFIX) (void)
{
- if (T0 & 0x03) {
+ if (unlikely(T0 & 0x03)) {
do_raise_exception(EXCP_ALIGN);
} else {
- T1 = glue(ldl, MEMSUFFIX)(T0);
- regs->reserve = T0;
+ T1 = glue(ldl, MEMSUFFIX)((uint32_t)T0);
+ regs->reserve = (uint32_t)T0;
}
RETURN();
}
-PPC_OP(glue(lwarx_le, MEMSUFFIX))
+#if defined(TARGET_PPC64)
+void OPPROTO glue(op_lwarx_64, MEMSUFFIX) (void)
{
- if (T0 & 0x03) {
+ if (unlikely(T0 & 0x03)) {
do_raise_exception(EXCP_ALIGN);
} else {
- T1 = glue(ld32r, MEMSUFFIX)(T0);
- regs->reserve = T0;
+ T1 = glue(ldl, MEMSUFFIX)((uint64_t)T0);
+ regs->reserve = (uint64_t)T0;
}
RETURN();
}
+void OPPROTO glue(op_ldarx, MEMSUFFIX) (void)
+{
+ if (unlikely(T0 & 0x03)) {
+ do_raise_exception(EXCP_ALIGN);
+ } else {
+ T1 = glue(ldq, MEMSUFFIX)((uint32_t)T0);
+ regs->reserve = (uint32_t)T0;
+ }
+ RETURN();
+}
+
+void OPPROTO glue(op_ldarx_64, MEMSUFFIX) (void)
+{
+ if (unlikely(T0 & 0x03)) {
+ do_raise_exception(EXCP_ALIGN);
+ } else {
+ T1 = glue(ldq, MEMSUFFIX)((uint64_t)T0);
+ regs->reserve = (uint64_t)T0;
+ }
+ RETURN();
+}
+#endif
+
+void OPPROTO glue(op_lwarx_le, MEMSUFFIX) (void)
+{
+ if (unlikely(T0 & 0x03)) {
+ do_raise_exception(EXCP_ALIGN);
+ } else {
+ T1 = glue(ld32r, MEMSUFFIX)((uint32_t)T0);
+ regs->reserve = (uint32_t)T0;
+ }
+ RETURN();
+}
+
+#if defined(TARGET_PPC64)
+void OPPROTO glue(op_lwarx_le_64, MEMSUFFIX) (void)
+{
+ if (unlikely(T0 & 0x03)) {
+ do_raise_exception(EXCP_ALIGN);
+ } else {
+ T1 = glue(ld32r, MEMSUFFIX)((uint64_t)T0);
+ regs->reserve = (uint64_t)T0;
+ }
+ RETURN();
+}
+
+void OPPROTO glue(op_ldarx_le, MEMSUFFIX) (void)
+{
+ if (unlikely(T0 & 0x03)) {
+ do_raise_exception(EXCP_ALIGN);
+ } else {
+ T1 = glue(ld64r, MEMSUFFIX)((uint32_t)T0);
+ regs->reserve = (uint32_t)T0;
+ }
+ RETURN();
+}
+
+void OPPROTO glue(op_ldarx_le_64, MEMSUFFIX) (void)
+{
+ if (unlikely(T0 & 0x03)) {
+ do_raise_exception(EXCP_ALIGN);
+ } else {
+ T1 = glue(ld64r, MEMSUFFIX)((uint64_t)T0);
+ regs->reserve = (uint64_t)T0;
+ }
+ RETURN();
+}
+#endif
+
/* Store with reservation */
-PPC_OP(glue(stwcx, MEMSUFFIX))
+void OPPROTO glue(op_stwcx, MEMSUFFIX) (void)
{
- if (T0 & 0x03) {
+ if (unlikely(T0 & 0x03)) {
do_raise_exception(EXCP_ALIGN);
} else {
- if (regs->reserve != T0) {
+ if (unlikely(regs->reserve != (uint32_t)T0)) {
env->crf[0] = xer_ov;
} else {
- glue(stl, MEMSUFFIX)(T0, T1);
+ glue(stl, MEMSUFFIX)((uint32_t)T0, T1);
env->crf[0] = xer_ov | 0x02;
}
}
- regs->reserve = 0;
+ regs->reserve = -1;
RETURN();
}
-PPC_OP(glue(stwcx_le, MEMSUFFIX))
+#if defined(TARGET_PPC64)
+void OPPROTO glue(op_stwcx_64, MEMSUFFIX) (void)
{
- if (T0 & 0x03) {
+ if (unlikely(T0 & 0x03)) {
do_raise_exception(EXCP_ALIGN);
} else {
- if (regs->reserve != T0) {
+ if (unlikely(regs->reserve != (uint64_t)T0)) {
env->crf[0] = xer_ov;
} else {
- glue(st32r, MEMSUFFIX)(T0, T1);
+ glue(stl, MEMSUFFIX)((uint64_t)T0, T1);
env->crf[0] = xer_ov | 0x02;
}
}
- regs->reserve = 0;
+ regs->reserve = -1;
RETURN();
}
-PPC_OP(glue(dcbz, MEMSUFFIX))
+void OPPROTO glue(op_stdcx, MEMSUFFIX) (void)
{
- glue(stl, MEMSUFFIX)(T0 + 0x00, 0);
- glue(stl, MEMSUFFIX)(T0 + 0x04, 0);
- glue(stl, MEMSUFFIX)(T0 + 0x08, 0);
- glue(stl, MEMSUFFIX)(T0 + 0x0C, 0);
- glue(stl, MEMSUFFIX)(T0 + 0x10, 0);
- glue(stl, MEMSUFFIX)(T0 + 0x14, 0);
- glue(stl, MEMSUFFIX)(T0 + 0x18, 0);
- glue(stl, MEMSUFFIX)(T0 + 0x1C, 0);
+ if (unlikely(T0 & 0x03)) {
+ do_raise_exception(EXCP_ALIGN);
+ } else {
+ if (unlikely(regs->reserve != (uint32_t)T0)) {
+ env->crf[0] = xer_ov;
+ } else {
+ glue(stq, MEMSUFFIX)((uint32_t)T0, T1);
+ env->crf[0] = xer_ov | 0x02;
+ }
+ }
+ regs->reserve = -1;
RETURN();
}
+void OPPROTO glue(op_stdcx_64, MEMSUFFIX) (void)
+{
+ if (unlikely(T0 & 0x03)) {
+ do_raise_exception(EXCP_ALIGN);
+ } else {
+ if (unlikely(regs->reserve != (uint64_t)T0)) {
+ env->crf[0] = xer_ov;
+ } else {
+ glue(stq, MEMSUFFIX)((uint64_t)T0, T1);
+ env->crf[0] = xer_ov | 0x02;
+ }
+ }
+ regs->reserve = -1;
+ RETURN();
+}
+#endif
+
+void OPPROTO glue(op_stwcx_le, MEMSUFFIX) (void)
+{
+ if (unlikely(T0 & 0x03)) {
+ do_raise_exception(EXCP_ALIGN);
+ } else {
+ if (unlikely(regs->reserve != (uint32_t)T0)) {
+ env->crf[0] = xer_ov;
+ } else {
+ glue(st32r, MEMSUFFIX)((uint32_t)T0, T1);
+ env->crf[0] = xer_ov | 0x02;
+ }
+ }
+ regs->reserve = -1;
+ RETURN();
+}
+
+#if defined(TARGET_PPC64)
+void OPPROTO glue(op_stwcx_le_64, MEMSUFFIX) (void)
+{
+ if (unlikely(T0 & 0x03)) {
+ do_raise_exception(EXCP_ALIGN);
+ } else {
+ if (unlikely(regs->reserve != (uint64_t)T0)) {
+ env->crf[0] = xer_ov;
+ } else {
+ glue(st32r, MEMSUFFIX)((uint64_t)T0, T1);
+ env->crf[0] = xer_ov | 0x02;
+ }
+ }
+ regs->reserve = -1;
+ RETURN();
+}
+
+void OPPROTO glue(op_stdcx_le, MEMSUFFIX) (void)
+{
+ if (unlikely(T0 & 0x03)) {
+ do_raise_exception(EXCP_ALIGN);
+ } else {
+ if (unlikely(regs->reserve != (uint32_t)T0)) {
+ env->crf[0] = xer_ov;
+ } else {
+ glue(st64r, MEMSUFFIX)((uint32_t)T0, T1);
+ env->crf[0] = xer_ov | 0x02;
+ }
+ }
+ regs->reserve = -1;
+ RETURN();
+}
+
+void OPPROTO glue(op_stdcx_le_64, MEMSUFFIX) (void)
+{
+ if (unlikely(T0 & 0x03)) {
+ do_raise_exception(EXCP_ALIGN);
+ } else {
+ if (unlikely(regs->reserve != (uint64_t)T0)) {
+ env->crf[0] = xer_ov;
+ } else {
+ glue(st64r, MEMSUFFIX)((uint64_t)T0, T1);
+ env->crf[0] = xer_ov | 0x02;
+ }
+ }
+ regs->reserve = -1;
+ RETURN();
+}
+#endif
+
+void OPPROTO glue(op_dcbz, MEMSUFFIX) (void)
+{
+ glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x00), 0);
+ glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x04), 0);
+ glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x08), 0);
+ glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x0C), 0);
+ glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x10), 0);
+ glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x14), 0);
+ glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x18), 0);
+ glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x1C), 0);
+#if DCACHE_LINE_SIZE == 64
+ /* XXX: cache line size should be 64 for POWER & PowerPC 601 */
+ glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x20UL), 0);
+ glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x24UL), 0);
+ glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x28UL), 0);
+ glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x2CUL), 0);
+ glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x30UL), 0);
+ glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x34UL), 0);
+ glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x38UL), 0);
+ glue(stl, MEMSUFFIX)((uint32_t)(T0 + 0x3CUL), 0);
+#endif
+ RETURN();
+}
+
+#if defined(TARGET_PPC64)
+void OPPROTO glue(op_dcbz_64, MEMSUFFIX) (void)
+{
+ glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x00), 0);
+ glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x04), 0);
+ glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x08), 0);
+ glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x0C), 0);
+ glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x10), 0);
+ glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x14), 0);
+ glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x18), 0);
+ glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x1C), 0);
+#if DCACHE_LINE_SIZE == 64
+ /* XXX: cache line size should be 64 for POWER & PowerPC 601 */
+ glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x20UL), 0);
+ glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x24UL), 0);
+ glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x28UL), 0);
+ glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x2CUL), 0);
+ glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x30UL), 0);
+ glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x34UL), 0);
+ glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x38UL), 0);
+ glue(stl, MEMSUFFIX)((uint64_t)(T0 + 0x3CUL), 0);
+#endif
+ RETURN();
+}
+#endif
+
+/* Instruction cache block invalidate */
+void OPPROTO glue(op_icbi, MEMSUFFIX) (void)
+{
+ glue(do_icbi, MEMSUFFIX)();
+ RETURN();
+}
+
+#if defined(TARGET_PPC64)
+void OPPROTO glue(op_icbi_64, MEMSUFFIX) (void)
+{
+ glue(do_icbi_64, MEMSUFFIX)();
+ RETURN();
+}
+#endif
+
/* External access */
-PPC_OP(glue(eciwx, MEMSUFFIX))
+void OPPROTO glue(op_eciwx, MEMSUFFIX) (void)
{
- T1 = glue(ldl, MEMSUFFIX)(T0);
+ T1 = glue(ldl, MEMSUFFIX)((uint32_t)T0);
RETURN();
}
-PPC_OP(glue(ecowx, MEMSUFFIX))
+#if defined(TARGET_PPC64)
+void OPPROTO glue(op_eciwx_64, MEMSUFFIX) (void)
{
- glue(stl, MEMSUFFIX)(T0, T1);
+ T1 = glue(ldl, MEMSUFFIX)((uint64_t)T0);
RETURN();
}
+#endif
-PPC_OP(glue(eciwx_le, MEMSUFFIX))
+void OPPROTO glue(op_ecowx, MEMSUFFIX) (void)
{
- T1 = glue(ld32r, MEMSUFFIX)(T0);
+ glue(stl, MEMSUFFIX)((uint32_t)T0, T1);
RETURN();
}
-PPC_OP(glue(ecowx_le, MEMSUFFIX))
+#if defined(TARGET_PPC64)
+void OPPROTO glue(op_ecowx_64, MEMSUFFIX) (void)
{
- glue(st32r, MEMSUFFIX)(T0, T1);
+ glue(stl, MEMSUFFIX)((uint64_t)T0, T1);
RETURN();
}
+#endif
+void OPPROTO glue(op_eciwx_le, MEMSUFFIX) (void)
+{
+ T1 = glue(ld32r, MEMSUFFIX)((uint32_t)T0);
+ RETURN();
+}
+
+#if defined(TARGET_PPC64)
+void OPPROTO glue(op_eciwx_le_64, MEMSUFFIX) (void)
+{
+ T1 = glue(ld32r, MEMSUFFIX)((uint64_t)T0);
+ RETURN();
+}
+#endif
+
+void OPPROTO glue(op_ecowx_le, MEMSUFFIX) (void)
+{
+ glue(st32r, MEMSUFFIX)((uint32_t)T0, T1);
+ RETURN();
+}
+
+#if defined(TARGET_PPC64)
+void OPPROTO glue(op_ecowx_le_64, MEMSUFFIX) (void)
+{
+ glue(st32r, MEMSUFFIX)((uint64_t)T0, T1);
+ RETURN();
+}
+#endif
+
+/* XXX: those micro-ops need tests ! */
+/* PowerPC 601 specific instructions (POWER bridge) */
+void OPPROTO glue(op_POWER_lscbx, MEMSUFFIX) (void)
+{
+ /* When byte count is 0, do nothing */
+ if (likely(T1 != 0)) {
+ glue(do_POWER_lscbx, MEMSUFFIX)(PARAM1, PARAM2, PARAM3);
+ }
+ RETURN();
+}
+
+/* POWER2 quad load and store */
+/* XXX: TAGs are not managed */
+void OPPROTO glue(op_POWER2_lfq, MEMSUFFIX) (void)
+{
+ glue(do_POWER2_lfq, MEMSUFFIX)();
+ RETURN();
+}
+
+void glue(op_POWER2_lfq_le, MEMSUFFIX) (void)
+{
+ glue(do_POWER2_lfq_le, MEMSUFFIX)();
+ RETURN();
+}
+
+void OPPROTO glue(op_POWER2_stfq, MEMSUFFIX) (void)
+{
+ glue(do_POWER2_stfq, MEMSUFFIX)();
+ RETURN();
+}
+
+void OPPROTO glue(op_POWER2_stfq_le, MEMSUFFIX) (void)
+{
+ glue(do_POWER2_stfq_le, MEMSUFFIX)();
+ RETURN();
+}
+
+#if defined(TARGET_PPCEMB)
+/* SPE extension */
+#define _PPC_SPE_LD_OP(name, op) \
+void OPPROTO glue(glue(op_spe_l, name), MEMSUFFIX) (void) \
+{ \
+ T1_64 = glue(op, MEMSUFFIX)((uint32_t)T0); \
+ RETURN(); \
+}
+
+#if defined(TARGET_PPC64)
+#define _PPC_SPE_LD_OP_64(name, op) \
+void OPPROTO glue(glue(glue(op_spe_l, name), _64), MEMSUFFIX) (void) \
+{ \
+ T1_64 = glue(op, MEMSUFFIX)((uint64_t)T0); \
+ RETURN(); \
+}
+#define PPC_SPE_LD_OP(name, op) \
+_PPC_SPE_LD_OP(name, op); \
+_PPC_SPE_LD_OP_64(name, op)
+#else
+#define PPC_SPE_LD_OP(name, op) \
+_PPC_SPE_LD_OP(name, op)
+#endif
+
+
+#define _PPC_SPE_ST_OP(name, op) \
+void OPPROTO glue(glue(op_spe_st, name), MEMSUFFIX) (void) \
+{ \
+ glue(op, MEMSUFFIX)((uint32_t)T0, T1_64); \
+ RETURN(); \
+}
+
+#if defined(TARGET_PPC64)
+#define _PPC_SPE_ST_OP_64(name, op) \
+void OPPROTO glue(glue(glue(op_spe_st, name), _64), MEMSUFFIX) (void) \
+{ \
+ glue(op, MEMSUFFIX)((uint64_t)T0, T1_64); \
+ RETURN(); \
+}
+#define PPC_SPE_ST_OP(name, op) \
+_PPC_SPE_ST_OP(name, op); \
+_PPC_SPE_ST_OP_64(name, op)
+#else
+#define PPC_SPE_ST_OP(name, op) \
+_PPC_SPE_ST_OP(name, op)
+#endif
+
+#if !defined(TARGET_PPC64)
+PPC_SPE_LD_OP(dd, ldq);
+PPC_SPE_ST_OP(dd, stq);
+PPC_SPE_LD_OP(dd_le, ld64r);
+PPC_SPE_ST_OP(dd_le, st64r);
+#endif
+static inline uint64_t glue(spe_ldw, MEMSUFFIX) (target_ulong EA)
+{
+ uint64_t ret;
+ ret = (uint64_t)glue(ldl, MEMSUFFIX)(EA) << 32;
+ ret |= (uint64_t)glue(ldl, MEMSUFFIX)(EA + 4);
+ return ret;
+}
+PPC_SPE_LD_OP(dw, spe_ldw);
+static inline void glue(spe_stdw, MEMSUFFIX) (target_ulong EA, uint64_t data)
+{
+ glue(stl, MEMSUFFIX)(EA, data >> 32);
+ glue(stl, MEMSUFFIX)(EA + 4, data);
+}
+PPC_SPE_ST_OP(dw, spe_stdw);
+static inline uint64_t glue(spe_ldw_le, MEMSUFFIX) (target_ulong EA)
+{
+ uint64_t ret;
+ ret = (uint64_t)glue(ld32r, MEMSUFFIX)(EA) << 32;
+ ret |= (uint64_t)glue(ld32r, MEMSUFFIX)(EA + 4);
+ return ret;
+}
+PPC_SPE_LD_OP(dw_le, spe_ldw_le);
+static inline void glue(spe_stdw_le, MEMSUFFIX) (target_ulong EA,
+ uint64_t data)
+{
+ glue(st32r, MEMSUFFIX)(EA, data >> 32);
+ glue(st32r, MEMSUFFIX)(EA + 4, data);
+}
+PPC_SPE_ST_OP(dw_le, spe_stdw_le);
+static inline uint64_t glue(spe_ldh, MEMSUFFIX) (target_ulong EA)
+{
+ uint64_t ret;
+ ret = (uint64_t)glue(lduw, MEMSUFFIX)(EA) << 48;
+ ret |= (uint64_t)glue(lduw, MEMSUFFIX)(EA + 2) << 32;
+ ret |= (uint64_t)glue(lduw, MEMSUFFIX)(EA + 4) << 16;
+ ret |= (uint64_t)glue(lduw, MEMSUFFIX)(EA + 6);
+ return ret;
+}
+PPC_SPE_LD_OP(dh, spe_ldh);
+static inline void glue(spe_stdh, MEMSUFFIX) (target_ulong EA, uint64_t data)
+{
+ glue(stw, MEMSUFFIX)(EA, data >> 48);
+ glue(stw, MEMSUFFIX)(EA + 2, data >> 32);
+ glue(stw, MEMSUFFIX)(EA + 4, data >> 16);
+ glue(stw, MEMSUFFIX)(EA + 6, data);
+}
+PPC_SPE_ST_OP(dh, spe_stdh);
+static inline uint64_t glue(spe_ldh_le, MEMSUFFIX) (target_ulong EA)
+{
+ uint64_t ret;
+ ret = (uint64_t)glue(ld16r, MEMSUFFIX)(EA) << 48;
+ ret |= (uint64_t)glue(ld16r, MEMSUFFIX)(EA + 2) << 32;
+ ret |= (uint64_t)glue(ld16r, MEMSUFFIX)(EA + 4) << 16;
+ ret |= (uint64_t)glue(ld16r, MEMSUFFIX)(EA + 6);
+ return ret;
+}
+PPC_SPE_LD_OP(dh_le, spe_ldh_le);
+static inline void glue(spe_stdh_le, MEMSUFFIX) (target_ulong EA,
+ uint64_t data)
+{
+ glue(st16r, MEMSUFFIX)(EA, data >> 48);
+ glue(st16r, MEMSUFFIX)(EA + 2, data >> 32);
+ glue(st16r, MEMSUFFIX)(EA + 4, data >> 16);
+ glue(st16r, MEMSUFFIX)(EA + 6, data);
+}
+PPC_SPE_ST_OP(dh_le, spe_stdh_le);
+static inline uint64_t glue(spe_lwhe, MEMSUFFIX) (target_ulong EA)
+{
+ uint64_t ret;
+ ret = (uint64_t)glue(lduw, MEMSUFFIX)(EA) << 48;
+ ret |= (uint64_t)glue(lduw, MEMSUFFIX)(EA + 2) << 16;
+ return ret;
+}
+PPC_SPE_LD_OP(whe, spe_lwhe);
+static inline void glue(spe_stwhe, MEMSUFFIX) (target_ulong EA, uint64_t data)
+{
+ glue(stw, MEMSUFFIX)(EA, data >> 48);
+ glue(stw, MEMSUFFIX)(EA + 2, data >> 16);
+}
+PPC_SPE_ST_OP(whe, spe_stwhe);
+static inline uint64_t glue(spe_lwhe_le, MEMSUFFIX) (target_ulong EA)
+{
+ uint64_t ret;
+ ret = (uint64_t)glue(ld16r, MEMSUFFIX)(EA) << 48;
+ ret |= (uint64_t)glue(ld16r, MEMSUFFIX)(EA + 2) << 16;
+ return ret;
+}
+PPC_SPE_LD_OP(whe_le, spe_lwhe_le);
+static inline void glue(spe_stwhe_le, MEMSUFFIX) (target_ulong EA,
+ uint64_t data)
+{
+ glue(st16r, MEMSUFFIX)(EA, data >> 48);
+ glue(st16r, MEMSUFFIX)(EA + 2, data >> 16);
+}
+PPC_SPE_ST_OP(whe_le, spe_stwhe_le);
+static inline uint64_t glue(spe_lwhou, MEMSUFFIX) (target_ulong EA)
+{
+ uint64_t ret;
+ ret = (uint64_t)glue(lduw, MEMSUFFIX)(EA) << 32;
+ ret |= (uint64_t)glue(lduw, MEMSUFFIX)(EA + 2);
+ return ret;
+}
+PPC_SPE_LD_OP(whou, spe_lwhou);
+static inline uint64_t glue(spe_lwhos, MEMSUFFIX) (target_ulong EA)
+{
+ uint64_t ret;
+ ret = ((uint64_t)((int32_t)glue(ldsw, MEMSUFFIX)(EA))) << 32;
+ ret |= (uint64_t)((int32_t)glue(ldsw, MEMSUFFIX)(EA + 2));
+ return ret;
+}
+PPC_SPE_LD_OP(whos, spe_lwhos);
+static inline void glue(spe_stwho, MEMSUFFIX) (target_ulong EA, uint64_t data)
+{
+ glue(stw, MEMSUFFIX)(EA, data >> 32);
+ glue(stw, MEMSUFFIX)(EA + 2, data);
+}
+PPC_SPE_ST_OP(who, spe_stwho);
+static inline uint64_t glue(spe_lwhou_le, MEMSUFFIX) (target_ulong EA)
+{
+ uint64_t ret;
+ ret = (uint64_t)glue(ld16r, MEMSUFFIX)(EA) << 32;
+ ret |= (uint64_t)glue(ld16r, MEMSUFFIX)(EA + 2);
+ return ret;
+}
+PPC_SPE_LD_OP(whou_le, spe_lwhou_le);
+static inline uint64_t glue(spe_lwhos_le, MEMSUFFIX) (target_ulong EA)
+{
+ uint64_t ret;
+ ret = ((uint64_t)((int32_t)glue(ld16rs, MEMSUFFIX)(EA))) << 32;
+ ret |= (uint64_t)((int32_t)glue(ld16rs, MEMSUFFIX)(EA + 2));
+ return ret;
+}
+PPC_SPE_LD_OP(whos_le, spe_lwhos_le);
+static inline void glue(spe_stwho_le, MEMSUFFIX) (target_ulong EA,
+ uint64_t data)
+{
+ glue(st16r, MEMSUFFIX)(EA, data >> 32);
+ glue(st16r, MEMSUFFIX)(EA + 2, data);
+}
+PPC_SPE_ST_OP(who_le, spe_stwho_le);
+#if !defined(TARGET_PPC64)
+static inline void glue(spe_stwwo, MEMSUFFIX) (target_ulong EA, uint64_t data)
+{
+ glue(stl, MEMSUFFIX)(EA, data);
+}
+PPC_SPE_ST_OP(wwo, spe_stwwo);
+static inline void glue(spe_stwwo_le, MEMSUFFIX) (target_ulong EA,
+ uint64_t data)
+{
+ glue(st32r, MEMSUFFIX)(EA, data);
+}
+PPC_SPE_ST_OP(wwo_le, spe_stwwo_le);
+#endif
+static inline uint64_t glue(spe_lh, MEMSUFFIX) (target_ulong EA)
+{
+ uint16_t tmp;
+ tmp = glue(lduw, MEMSUFFIX)(EA);
+ return ((uint64_t)tmp << 48) | ((uint64_t)tmp << 16);
+}
+PPC_SPE_LD_OP(h, spe_lh);
+static inline uint64_t glue(spe_lh_le, MEMSUFFIX) (target_ulong EA)
+{
+ uint16_t tmp;
+ tmp = glue(ld16r, MEMSUFFIX)(EA);
+ return ((uint64_t)tmp << 48) | ((uint64_t)tmp << 16);
+}
+PPC_SPE_LD_OP(h_le, spe_lh_le);
+static inline uint64_t glue(spe_lwwsplat, MEMSUFFIX) (target_ulong EA)
+{
+ uint32_t tmp;
+ tmp = glue(ldl, MEMSUFFIX)(EA);
+ return ((uint64_t)tmp << 32) | (uint64_t)tmp;
+}
+PPC_SPE_LD_OP(wwsplat, spe_lwwsplat);
+static inline uint64_t glue(spe_lwwsplat_le, MEMSUFFIX) (target_ulong EA)
+{
+ uint32_t tmp;
+ tmp = glue(ld32r, MEMSUFFIX)(EA);
+ return ((uint64_t)tmp << 32) | (uint64_t)tmp;
+}
+PPC_SPE_LD_OP(wwsplat_le, spe_lwwsplat_le);
+static inline uint64_t glue(spe_lwhsplat, MEMSUFFIX) (target_ulong EA)
+{
+ uint64_t ret;
+ uint16_t tmp;
+ tmp = glue(lduw, MEMSUFFIX)(EA);
+ ret = ((uint64_t)tmp << 48) | ((uint64_t)tmp << 32);
+ tmp = glue(lduw, MEMSUFFIX)(EA + 2);
+ ret |= ((uint64_t)tmp << 16) | (uint64_t)tmp;
+ return ret;
+}
+PPC_SPE_LD_OP(whsplat, spe_lwhsplat);
+static inline uint64_t glue(spe_lwhsplat_le, MEMSUFFIX) (target_ulong EA)
+{
+ uint64_t ret;
+ uint16_t tmp;
+ tmp = glue(ld16r, MEMSUFFIX)(EA);
+ ret = ((uint64_t)tmp << 48) | ((uint64_t)tmp << 32);
+ tmp = glue(ld16r, MEMSUFFIX)(EA + 2);
+ ret |= ((uint64_t)tmp << 16) | (uint64_t)tmp;
+ return ret;
+}
+PPC_SPE_LD_OP(whsplat_le, spe_lwhsplat_le);
+#endif /* defined(TARGET_PPCEMB) */
+
#undef MEMSUFFIX
Modified: trunk/src/host/qemu-neo1973/target-ppc/op_template.h
===================================================================
--- trunk/src/host/qemu-neo1973/target-ppc/op_template.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/target-ppc/op_template.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -1,7 +1,7 @@
/*
* PowerPC emulation micro-operations for qemu.
*
- * Copyright (c) 2003-2005 Jocelyn Mayer
+ * Copyright (c) 2003-2007 Jocelyn Mayer
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -19,108 +19,140 @@
*/
/* General purpose registers moves */
-void OPPROTO glue(op_load_gpr_T0_gpr, REG)(void)
+void OPPROTO glue(op_load_gpr_T0_gpr, REG) (void)
{
T0 = regs->gpr[REG];
RETURN();
}
-void OPPROTO glue(op_load_gpr_T1_gpr, REG)(void)
+void OPPROTO glue(op_load_gpr_T1_gpr, REG) (void)
{
T1 = regs->gpr[REG];
RETURN();
}
-void OPPROTO glue(op_load_gpr_T2_gpr, REG)(void)
+void OPPROTO glue(op_load_gpr_T2_gpr, REG) (void)
{
T2 = regs->gpr[REG];
RETURN();
}
-void OPPROTO glue(op_store_T0_gpr_gpr, REG)(void)
+void OPPROTO glue(op_store_T0_gpr_gpr, REG) (void)
{
regs->gpr[REG] = T0;
RETURN();
}
-void OPPROTO glue(op_store_T1_gpr_gpr, REG)(void)
+void OPPROTO glue(op_store_T1_gpr_gpr, REG) (void)
{
regs->gpr[REG] = T1;
RETURN();
}
-void OPPROTO glue(op_store_T2_gpr_gpr, REG)(void)
+#if 0 // unused
+void OPPROTO glue(op_store_T2_gpr_gpr, REG) (void)
{
regs->gpr[REG] = T2;
RETURN();
}
+#endif
+#if defined(TARGET_PPCEMB)
+void OPPROTO glue(op_load_gpr64_T0_gpr, REG) (void)
+{
+ T0_64 = regs->gpr[REG];
+ RETURN();
+}
+
+void OPPROTO glue(op_load_gpr64_T1_gpr, REG) (void)
+{
+ T1_64 = regs->gpr[REG];
+ RETURN();
+}
+
+#if 0 // unused
+void OPPROTO glue(op_load_gpr64_T2_gpr, REG) (void)
+{
+ T2_64 = regs->gpr[REG];
+ RETURN();
+}
+#endif
+
+void OPPROTO glue(op_store_T0_gpr64_gpr, REG) (void)
+{
+ regs->gpr[REG] = T0_64;
+ RETURN();
+}
+
+void OPPROTO glue(op_store_T1_gpr64_gpr, REG) (void)
+{
+ regs->gpr[REG] = T1_64;
+ RETURN();
+}
+
+#if 0 // unused
+void OPPROTO glue(op_store_T2_gpr64_gpr, REG) (void)
+{
+ regs->gpr[REG] = T2_64;
+ RETURN();
+}
+#endif
+#endif /* defined(TARGET_PPCEMB) */
+
#if REG <= 7
/* Condition register moves */
-void OPPROTO glue(op_load_crf_T0_crf, REG)(void)
+void OPPROTO glue(op_load_crf_T0_crf, REG) (void)
{
T0 = regs->crf[REG];
RETURN();
}
-void OPPROTO glue(op_load_crf_T1_crf, REG)(void)
+void OPPROTO glue(op_load_crf_T1_crf, REG) (void)
{
T1 = regs->crf[REG];
RETURN();
}
-void OPPROTO glue(op_store_T0_crf_crf, REG)(void)
+void OPPROTO glue(op_store_T0_crf_crf, REG) (void)
{
regs->crf[REG] = T0;
RETURN();
}
-void OPPROTO glue(op_store_T1_crf_crf, REG)(void)
+void OPPROTO glue(op_store_T1_crf_crf, REG) (void)
{
regs->crf[REG] = T1;
RETURN();
}
/* Floating point condition and status register moves */
-void OPPROTO glue(op_load_fpscr_T0_fpscr, REG)(void)
+void OPPROTO glue(op_load_fpscr_T0_fpscr, REG) (void)
{
T0 = regs->fpscr[REG];
RETURN();
}
#if REG == 0
-void OPPROTO glue(op_store_T0_fpscr_fpscr, REG)(void)
+void OPPROTO glue(op_store_T0_fpscr_fpscr, REG) (void)
{
regs->fpscr[REG] = (regs->fpscr[REG] & 0x9) | (T0 & ~0x9);
RETURN();
}
-void OPPROTO glue(op_store_T0_fpscri_fpscr, REG)(void)
+void OPPROTO glue(op_clear_fpscr_fpscr, REG) (void)
{
- regs->fpscr[REG] = (regs->fpscr[REG] & ~0x9) | (PARAM(1) & 0x9);
- RETURN();
-}
-
-void OPPROTO glue(op_clear_fpscr_fpscr, REG)(void)
-{
regs->fpscr[REG] = (regs->fpscr[REG] & 0x9);
RETURN();
}
#else
-void OPPROTO glue(op_store_T0_fpscr_fpscr, REG)(void)
+void OPPROTO glue(op_store_T0_fpscr_fpscr, REG) (void)
{
regs->fpscr[REG] = T0;
RETURN();
}
-void OPPROTO glue(op_store_T0_fpscri_fpscr, REG)(void)
+void OPPROTO glue(op_clear_fpscr_fpscr, REG) (void)
{
- regs->fpscr[REG] = PARAM(1);
- RETURN();
-}
-
-void OPPROTO glue(op_clear_fpscr_fpscr, REG)(void)
-{
regs->fpscr[REG] = 0x0;
RETURN();
}
@@ -129,55 +161,42 @@
#endif /* REG <= 7 */
/* floating point registers moves */
-void OPPROTO glue(op_load_fpr_FT0_fpr, REG)(void)
+void OPPROTO glue(op_load_fpr_FT0_fpr, REG) (void)
{
FT0 = env->fpr[REG];
RETURN();
}
-void OPPROTO glue(op_store_FT0_fpr_fpr, REG)(void)
+void OPPROTO glue(op_store_FT0_fpr_fpr, REG) (void)
{
env->fpr[REG] = FT0;
RETURN();
}
-void OPPROTO glue(op_load_fpr_FT1_fpr, REG)(void)
+void OPPROTO glue(op_load_fpr_FT1_fpr, REG) (void)
{
FT1 = env->fpr[REG];
RETURN();
}
-void OPPROTO glue(op_store_FT1_fpr_fpr, REG)(void)
+void OPPROTO glue(op_store_FT1_fpr_fpr, REG) (void)
{
env->fpr[REG] = FT1;
RETURN();
}
-void OPPROTO glue(op_load_fpr_FT2_fpr, REG)(void)
+void OPPROTO glue(op_load_fpr_FT2_fpr, REG) (void)
{
FT2 = env->fpr[REG];
RETURN();
}
-void OPPROTO glue(op_store_FT2_fpr_fpr, REG)(void)
+#if 0 // unused
+void OPPROTO glue(op_store_FT2_fpr_fpr, REG) (void)
{
env->fpr[REG] = FT2;
RETURN();
}
-
-#if REG <= 15
-/* Segment register moves */
-void OPPROTO glue(op_load_sr, REG)(void)
-{
- T0 = env->sr[REG];
- RETURN();
-}
-
-void OPPROTO glue(op_store_sr, REG)(void)
-{
- do_store_sr(env, REG, T0);
- RETURN();
-}
#endif
#undef REG
Modified: trunk/src/host/qemu-neo1973/target-ppc/translate.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-ppc/translate.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/target-ppc/translate.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -1,7 +1,7 @@
/*
* PowerPC emulation for qemu: main translation routines.
*
- * Copyright (c) 2003-2005 Jocelyn Mayer
+ * Copyright (c) 2003-2007 Jocelyn Mayer
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -29,8 +29,10 @@
//#define DO_SINGLE_STEP
//#define PPC_DEBUG_DISAS
+//#define DEBUG_MEMORY_ACCESSES
+//#define DO_PPC_STATISTICS
-#ifdef USE_DIRECT_JUMP
+#if defined(USE_DIRECT_JUMP)
#define TBPARAM(x)
#else
#define TBPARAM(x) (long)(x)
@@ -48,7 +50,27 @@
#include "gen-op.h"
-#define GEN8(func, NAME) \
+static inline void gen_set_T0 (target_ulong val)
+{
+#if defined(TARGET_PPC64)
+ if (val >> 32)
+ gen_op_set_T0_64(val >> 32, val);
+ else
+#endif
+ gen_op_set_T0(val);
+}
+
+static inline void gen_set_T1 (target_ulong val)
+{
+#if defined(TARGET_PPC64)
+ if (val >> 32)
+ gen_op_set_T1_64(val >> 32, val);
+ else
+#endif
+ gen_op_set_T1(val);
+}
+
+#define GEN8(func, NAME) \
static GenOpFunc *NAME ## _table [8] = { \
NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3, \
NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \
@@ -70,7 +92,7 @@
NAME ## _table[n](); \
}
-#define GEN32(func, NAME) \
+#define GEN32(func, NAME) \
static GenOpFunc *NAME ## _table [32] = { \
NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3, \
NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \
@@ -96,25 +118,12 @@
GEN8(gen_op_load_fpscr_T0, gen_op_load_fpscr_T0_fpscr);
GEN8(gen_op_store_T0_fpscr, gen_op_store_T0_fpscr_fpscr);
GEN8(gen_op_clear_fpscr, gen_op_clear_fpscr_fpscr);
-static GenOpFunc1 *gen_op_store_T0_fpscri_fpscr_table[8] = {
- &gen_op_store_T0_fpscri_fpscr0,
- &gen_op_store_T0_fpscri_fpscr1,
- &gen_op_store_T0_fpscri_fpscr2,
- &gen_op_store_T0_fpscri_fpscr3,
- &gen_op_store_T0_fpscri_fpscr4,
- &gen_op_store_T0_fpscri_fpscr5,
- &gen_op_store_T0_fpscri_fpscr6,
- &gen_op_store_T0_fpscri_fpscr7,
-};
static inline void gen_op_store_T0_fpscri(int n, uint8_t param)
{
- (*gen_op_store_T0_fpscri_fpscr_table[n])(param);
+ gen_op_set_T0(param);
+ gen_op_store_T0_fpscr(n);
}
-/* Segment register moves */
-GEN16(gen_op_load_sr, gen_op_load_sr);
-GEN16(gen_op_store_sr, gen_op_store_sr);
-
/* General purpose registers moves */
GEN32(gen_op_load_gpr_T0, gen_op_load_gpr_T0_gpr);
GEN32(gen_op_load_gpr_T1, gen_op_load_gpr_T1_gpr);
@@ -122,7 +131,9 @@
GEN32(gen_op_store_T0_gpr, gen_op_store_T0_gpr_gpr);
GEN32(gen_op_store_T1_gpr, gen_op_store_T1_gpr_gpr);
+#if 0 // unused
GEN32(gen_op_store_T2_gpr, gen_op_store_T2_gpr_gpr);
+#endif
/* floating point registers moves */
GEN32(gen_op_load_fpr_FT0, gen_op_load_fpr_FT0_fpr);
@@ -130,10 +141,10 @@
GEN32(gen_op_load_fpr_FT2, gen_op_load_fpr_FT2_fpr);
GEN32(gen_op_store_FT0_fpr, gen_op_store_FT0_fpr_fpr);
GEN32(gen_op_store_FT1_fpr, gen_op_store_FT1_fpr_fpr);
+#if 0 // unused
GEN32(gen_op_store_FT2_fpr, gen_op_store_FT2_fpr_fpr);
+#endif
-static uint8_t spr_access[1024 / 2];
-
/* internal defines */
typedef struct DisasContext {
struct TranslationBlock *tb;
@@ -146,7 +157,13 @@
#if !defined(CONFIG_USER_ONLY)
int supervisor;
#endif
+#if defined(TARGET_PPC64)
+ int sf_mode;
+#endif
int fpu_enabled;
+#if defined(TARGET_PPCEMB)
+ int spe_enabled;
+#endif
ppc_spr_t *spr_cb; /* Needed to check rights for mfspr/mtspr */
int singlestep_enabled;
} DisasContext;
@@ -155,15 +172,40 @@
/* invalid bits */
uint32_t inval;
/* instruction type */
- uint32_t type;
+ uint64_t type;
/* handler */
void (*handler)(DisasContext *ctx);
+#if defined(DO_PPC_STATISTICS)
+ const unsigned char *oname;
+ uint64_t count;
+#endif
};
+static inline void gen_set_Rc0 (DisasContext *ctx)
+{
+#if defined(TARGET_PPC64)
+ if (ctx->sf_mode)
+ gen_op_cmpi_64(0);
+ else
+#endif
+ gen_op_cmpi(0);
+ gen_op_set_Rc0();
+}
+
+static inline void gen_update_nip (DisasContext *ctx, target_ulong nip)
+{
+#if defined(TARGET_PPC64)
+ if (ctx->sf_mode)
+ gen_op_update_nip_64(nip >> 32, nip);
+ else
+#endif
+ gen_op_update_nip(nip);
+}
+
#define RET_EXCP(ctx, excp, error) \
do { \
if ((ctx)->exception == EXCP_NONE) { \
- gen_op_update_nip((ctx)->nip); \
+ gen_update_nip(ctx, (ctx)->nip); \
} \
gen_op_raise_exception_err((excp), (error)); \
ctx->exception = (excp); \
@@ -181,7 +223,7 @@
/* Stop translation */
static inline void RET_STOP (DisasContext *ctx)
{
- gen_op_update_nip((ctx)->nip);
+ gen_update_nip(ctx, ctx->nip);
ctx->exception = EXCP_MTMSR;
}
@@ -278,7 +320,7 @@
/* Displacement */
EXTRACT_SHELPER(d, 0, 16);
/* Immediate address */
-static inline uint32_t LI (uint32_t opcode)
+static inline target_ulong LI (uint32_t opcode)
{
return (opcode >> 0) & 0x03FFFFFC;
}
@@ -296,13 +338,29 @@
EXTRACT_HELPER(LK, 0, 1);
/* Create a mask between <start> and <end> bits */
-static inline uint32_t MASK (uint32_t start, uint32_t end)
+static inline target_ulong MASK (uint32_t start, uint32_t end)
{
- uint32_t ret;
+ target_ulong ret;
- ret = (((uint32_t)(-1)) >> (start)) ^ (((uint32_t)(-1) >> (end)) >> 1);
- if (start > end)
- return ~ret;
+#if defined(TARGET_PPC64)
+ if (likely(start == 0)) {
+ ret = (uint64_t)(-1ULL) << (63 - end);
+ } else if (likely(end == 63)) {
+ ret = (uint64_t)(-1ULL) >> start;
+ }
+#else
+ if (likely(start == 0)) {
+ ret = (uint32_t)(-1ULL) << (31 - end);
+ } else if (likely(end == 31)) {
+ ret = (uint32_t)(-1ULL) >> start;
+ }
+#endif
+ else {
+ ret = (((target_ulong)(-1ULL)) >> (start)) ^
+ (((target_ulong)(-1ULL) >> (end)) >> 1);
+ if (unlikely(start > end))
+ return ~ret;
+ }
return ret;
}
@@ -313,13 +371,14 @@
#define OPC_ALIGN 4
#endif
#if defined(__APPLE__)
-#define OPCODES_SECTION \
+#define OPCODES_SECTION \
__attribute__ ((section("__TEXT,__opcodes"), unused, aligned (OPC_ALIGN) ))
#else
-#define OPCODES_SECTION \
+#define OPCODES_SECTION \
__attribute__ ((section(".opcodes"), unused, aligned (OPC_ALIGN) ))
#endif
+#if defined(DO_PPC_STATISTICS)
#define GEN_OPCODE(name, op1, op2, op3, invl, _typ) \
OPCODES_SECTION opcode_t opc_##name = { \
.opc1 = op1, \
@@ -330,9 +389,25 @@
.inval = invl, \
.type = _typ, \
.handler = &gen_##name, \
+ .oname = stringify(name), \
}, \
.oname = stringify(name), \
}
+#else
+#define GEN_OPCODE(name, op1, op2, op3, invl, _typ) \
+OPCODES_SECTION opcode_t opc_##name = { \
+ .opc1 = op1, \
+ .opc2 = op2, \
+ .opc3 = op3, \
+ .pad = { 0, }, \
+ .handler = { \
+ .inval = invl, \
+ .type = _typ, \
+ .handler = &gen_##name, \
+ }, \
+ .oname = stringify(name), \
+}
+#endif
#define GEN_OPCODE_MARK(name) \
OPCODES_SECTION opcode_t opc_##name = { \
@@ -364,131 +439,385 @@
};
/*** Integer arithmetic ***/
-#define __GEN_INT_ARITH2(name, opc1, opc2, opc3, inval) \
-GEN_HANDLER(name, opc1, opc2, opc3, inval, PPC_INTEGER) \
+#define __GEN_INT_ARITH2(name, opc1, opc2, opc3, inval, type) \
+GEN_HANDLER(name, opc1, opc2, opc3, inval, type) \
{ \
gen_op_load_gpr_T0(rA(ctx->opcode)); \
gen_op_load_gpr_T1(rB(ctx->opcode)); \
gen_op_##name(); \
- if (Rc(ctx->opcode) != 0) \
- gen_op_set_Rc0(); \
gen_op_store_T0_gpr(rD(ctx->opcode)); \
+ if (unlikely(Rc(ctx->opcode) != 0)) \
+ gen_set_Rc0(ctx); \
}
-#define __GEN_INT_ARITH2_O(name, opc1, opc2, opc3, inval) \
-GEN_HANDLER(name, opc1, opc2, opc3, inval, PPC_INTEGER) \
+#define __GEN_INT_ARITH2_O(name, opc1, opc2, opc3, inval, type) \
+GEN_HANDLER(name, opc1, opc2, opc3, inval, type) \
{ \
gen_op_load_gpr_T0(rA(ctx->opcode)); \
gen_op_load_gpr_T1(rB(ctx->opcode)); \
gen_op_##name(); \
- if (Rc(ctx->opcode) != 0) \
- gen_op_set_Rc0(); \
gen_op_store_T0_gpr(rD(ctx->opcode)); \
+ if (unlikely(Rc(ctx->opcode) != 0)) \
+ gen_set_Rc0(ctx); \
}
-#define __GEN_INT_ARITH1(name, opc1, opc2, opc3) \
-GEN_HANDLER(name, opc1, opc2, opc3, 0x0000F800, PPC_INTEGER) \
+#define __GEN_INT_ARITH1(name, opc1, opc2, opc3, type) \
+GEN_HANDLER(name, opc1, opc2, opc3, 0x0000F800, type) \
{ \
gen_op_load_gpr_T0(rA(ctx->opcode)); \
gen_op_##name(); \
- if (Rc(ctx->opcode) != 0) \
- gen_op_set_Rc0(); \
gen_op_store_T0_gpr(rD(ctx->opcode)); \
+ if (unlikely(Rc(ctx->opcode) != 0)) \
+ gen_set_Rc0(ctx); \
}
-#define __GEN_INT_ARITH1_O(name, opc1, opc2, opc3) \
-GEN_HANDLER(name, opc1, opc2, opc3, 0x0000F800, PPC_INTEGER) \
+#define __GEN_INT_ARITH1_O(name, opc1, opc2, opc3, type) \
+GEN_HANDLER(name, opc1, opc2, opc3, 0x0000F800, type) \
{ \
gen_op_load_gpr_T0(rA(ctx->opcode)); \
gen_op_##name(); \
- if (Rc(ctx->opcode) != 0) \
- gen_op_set_Rc0(); \
gen_op_store_T0_gpr(rD(ctx->opcode)); \
+ if (unlikely(Rc(ctx->opcode) != 0)) \
+ gen_set_Rc0(ctx); \
}
/* Two operands arithmetic functions */
-#define GEN_INT_ARITH2(name, opc1, opc2, opc3) \
-__GEN_INT_ARITH2(name, opc1, opc2, opc3, 0x00000000) \
-__GEN_INT_ARITH2_O(name##o, opc1, opc2, opc3 | 0x10, 0x00000000)
+#define GEN_INT_ARITH2(name, opc1, opc2, opc3, type) \
+__GEN_INT_ARITH2(name, opc1, opc2, opc3, 0x00000000, type) \
+__GEN_INT_ARITH2_O(name##o, opc1, opc2, opc3 | 0x10, 0x00000000, type)
/* Two operands arithmetic functions with no overflow allowed */
-#define GEN_INT_ARITHN(name, opc1, opc2, opc3) \
-__GEN_INT_ARITH2(name, opc1, opc2, opc3, 0x00000400)
+#define GEN_INT_ARITHN(name, opc1, opc2, opc3, type) \
+__GEN_INT_ARITH2(name, opc1, opc2, opc3, 0x00000400, type)
/* One operand arithmetic functions */
-#define GEN_INT_ARITH1(name, opc1, opc2, opc3) \
-__GEN_INT_ARITH1(name, opc1, opc2, opc3) \
-__GEN_INT_ARITH1_O(name##o, opc1, opc2, opc3 | 0x10)
+#define GEN_INT_ARITH1(name, opc1, opc2, opc3, type) \
+__GEN_INT_ARITH1(name, opc1, opc2, opc3, type) \
+__GEN_INT_ARITH1_O(name##o, opc1, opc2, opc3 | 0x10, type)
+#if defined(TARGET_PPC64)
+#define __GEN_INT_ARITH2_64(name, opc1, opc2, opc3, inval, type) \
+GEN_HANDLER(name, opc1, opc2, opc3, inval, type) \
+{ \
+ gen_op_load_gpr_T0(rA(ctx->opcode)); \
+ gen_op_load_gpr_T1(rB(ctx->opcode)); \
+ if (ctx->sf_mode) \
+ gen_op_##name##_64(); \
+ else \
+ gen_op_##name(); \
+ gen_op_store_T0_gpr(rD(ctx->opcode)); \
+ if (unlikely(Rc(ctx->opcode) != 0)) \
+ gen_set_Rc0(ctx); \
+}
+
+#define __GEN_INT_ARITH2_O_64(name, opc1, opc2, opc3, inval, type) \
+GEN_HANDLER(name, opc1, opc2, opc3, inval, type) \
+{ \
+ gen_op_load_gpr_T0(rA(ctx->opcode)); \
+ gen_op_load_gpr_T1(rB(ctx->opcode)); \
+ if (ctx->sf_mode) \
+ gen_op_##name##_64(); \
+ else \
+ gen_op_##name(); \
+ gen_op_store_T0_gpr(rD(ctx->opcode)); \
+ if (unlikely(Rc(ctx->opcode) != 0)) \
+ gen_set_Rc0(ctx); \
+}
+
+#define __GEN_INT_ARITH1_64(name, opc1, opc2, opc3, type) \
+GEN_HANDLER(name, opc1, opc2, opc3, 0x0000F800, type) \
+{ \
+ gen_op_load_gpr_T0(rA(ctx->opcode)); \
+ if (ctx->sf_mode) \
+ gen_op_##name##_64(); \
+ else \
+ gen_op_##name(); \
+ gen_op_store_T0_gpr(rD(ctx->opcode)); \
+ if (unlikely(Rc(ctx->opcode) != 0)) \
+ gen_set_Rc0(ctx); \
+}
+#define __GEN_INT_ARITH1_O_64(name, opc1, opc2, opc3, type) \
+GEN_HANDLER(name, opc1, opc2, opc3, 0x0000F800, type) \
+{ \
+ gen_op_load_gpr_T0(rA(ctx->opcode)); \
+ if (ctx->sf_mode) \
+ gen_op_##name##_64(); \
+ else \
+ gen_op_##name(); \
+ gen_op_store_T0_gpr(rD(ctx->opcode)); \
+ if (unlikely(Rc(ctx->opcode) != 0)) \
+ gen_set_Rc0(ctx); \
+}
+
+/* Two operands arithmetic functions */
+#define GEN_INT_ARITH2_64(name, opc1, opc2, opc3, type) \
+__GEN_INT_ARITH2_64(name, opc1, opc2, opc3, 0x00000000, type) \
+__GEN_INT_ARITH2_O_64(name##o, opc1, opc2, opc3 | 0x10, 0x00000000, type)
+
+/* Two operands arithmetic functions with no overflow allowed */
+#define GEN_INT_ARITHN_64(name, opc1, opc2, opc3, type) \
+__GEN_INT_ARITH2_64(name, opc1, opc2, opc3, 0x00000400, type)
+
+/* One operand arithmetic functions */
+#define GEN_INT_ARITH1_64(name, opc1, opc2, opc3, type) \
+__GEN_INT_ARITH1_64(name, opc1, opc2, opc3, type) \
+__GEN_INT_ARITH1_O_64(name##o, opc1, opc2, opc3 | 0x10, type)
+#else
+#define GEN_INT_ARITH2_64 GEN_INT_ARITH2
+#define GEN_INT_ARITHN_64 GEN_INT_ARITHN
+#define GEN_INT_ARITH1_64 GEN_INT_ARITH1
+#endif
+
/* add add. addo addo. */
-GEN_INT_ARITH2 (add, 0x1F, 0x0A, 0x08);
+static inline void gen_op_addo (void)
+{
+ gen_op_move_T2_T0();
+ gen_op_add();
+ gen_op_check_addo();
+}
+#if defined(TARGET_PPC64)
+#define gen_op_add_64 gen_op_add
+static inline void gen_op_addo_64 (void)
+{
+ gen_op_move_T2_T0();
+ gen_op_add();
+ gen_op_check_addo_64();
+}
+#endif
+GEN_INT_ARITH2_64 (add, 0x1F, 0x0A, 0x08, PPC_INTEGER);
/* addc addc. addco addco. */
-GEN_INT_ARITH2 (addc, 0x1F, 0x0A, 0x00);
+static inline void gen_op_addc (void)
+{
+ gen_op_move_T2_T0();
+ gen_op_add();
+ gen_op_check_addc();
+}
+static inline void gen_op_addco (void)
+{
+ gen_op_move_T2_T0();
+ gen_op_add();
+ gen_op_check_addc();
+ gen_op_check_addo();
+}
+#if defined(TARGET_PPC64)
+static inline void gen_op_addc_64 (void)
+{
+ gen_op_move_T2_T0();
+ gen_op_add();
+ gen_op_check_addc_64();
+}
+static inline void gen_op_addco_64 (void)
+{
+ gen_op_move_T2_T0();
+ gen_op_add();
+ gen_op_check_addc_64();
+ gen_op_check_addo_64();
+}
+#endif
+GEN_INT_ARITH2_64 (addc, 0x1F, 0x0A, 0x00, PPC_INTEGER);
/* adde adde. addeo addeo. */
-GEN_INT_ARITH2 (adde, 0x1F, 0x0A, 0x04);
+static inline void gen_op_addeo (void)
+{
+ gen_op_move_T2_T0();
+ gen_op_adde();
+ gen_op_check_addo();
+}
+#if defined(TARGET_PPC64)
+static inline void gen_op_addeo_64 (void)
+{
+ gen_op_move_T2_T0();
+ gen_op_adde_64();
+ gen_op_check_addo_64();
+}
+#endif
+GEN_INT_ARITH2_64 (adde, 0x1F, 0x0A, 0x04, PPC_INTEGER);
/* addme addme. addmeo addmeo. */
-GEN_INT_ARITH1 (addme, 0x1F, 0x0A, 0x07);
+static inline void gen_op_addme (void)
+{
+ gen_op_move_T1_T0();
+ gen_op_add_me();
+}
+#if defined(TARGET_PPC64)
+static inline void gen_op_addme_64 (void)
+{
+ gen_op_move_T1_T0();
+ gen_op_add_me_64();
+}
+#endif
+GEN_INT_ARITH1_64 (addme, 0x1F, 0x0A, 0x07, PPC_INTEGER);
/* addze addze. addzeo addzeo. */
-GEN_INT_ARITH1 (addze, 0x1F, 0x0A, 0x06);
+static inline void gen_op_addze (void)
+{
+ gen_op_move_T2_T0();
+ gen_op_add_ze();
+ gen_op_check_addc();
+}
+static inline void gen_op_addzeo (void)
+{
+ gen_op_move_T2_T0();
+ gen_op_add_ze();
+ gen_op_check_addc();
+ gen_op_check_addo();
+}
+#if defined(TARGET_PPC64)
+static inline void gen_op_addze_64 (void)
+{
+ gen_op_move_T2_T0();
+ gen_op_add_ze();
+ gen_op_check_addc_64();
+}
+static inline void gen_op_addzeo_64 (void)
+{
+ gen_op_move_T2_T0();
+ gen_op_add_ze();
+ gen_op_check_addc_64();
+ gen_op_check_addo_64();
+}
+#endif
+GEN_INT_ARITH1_64 (addze, 0x1F, 0x0A, 0x06, PPC_INTEGER);
/* divw divw. divwo divwo. */
-GEN_INT_ARITH2 (divw, 0x1F, 0x0B, 0x0F);
+GEN_INT_ARITH2 (divw, 0x1F, 0x0B, 0x0F, PPC_INTEGER);
/* divwu divwu. divwuo divwuo. */
-GEN_INT_ARITH2 (divwu, 0x1F, 0x0B, 0x0E);
+GEN_INT_ARITH2 (divwu, 0x1F, 0x0B, 0x0E, PPC_INTEGER);
/* mulhw mulhw. */
-GEN_INT_ARITHN (mulhw, 0x1F, 0x0B, 0x02);
+GEN_INT_ARITHN (mulhw, 0x1F, 0x0B, 0x02, PPC_INTEGER);
/* mulhwu mulhwu. */
-GEN_INT_ARITHN (mulhwu, 0x1F, 0x0B, 0x00);
+GEN_INT_ARITHN (mulhwu, 0x1F, 0x0B, 0x00, PPC_INTEGER);
/* mullw mullw. mullwo mullwo. */
-GEN_INT_ARITH2 (mullw, 0x1F, 0x0B, 0x07);
+GEN_INT_ARITH2 (mullw, 0x1F, 0x0B, 0x07, PPC_INTEGER);
/* neg neg. nego nego. */
-GEN_INT_ARITH1 (neg, 0x1F, 0x08, 0x03);
+GEN_INT_ARITH1_64 (neg, 0x1F, 0x08, 0x03, PPC_INTEGER);
/* subf subf. subfo subfo. */
-GEN_INT_ARITH2 (subf, 0x1F, 0x08, 0x01);
+static inline void gen_op_subfo (void)
+{
+ gen_op_move_T2_T0();
+ gen_op_subf();
+ gen_op_check_subfo();
+}
+#if defined(TARGET_PPC64)
+#define gen_op_subf_64 gen_op_subf
+static inline void gen_op_subfo_64 (void)
+{
+ gen_op_move_T2_T0();
+ gen_op_subf();
+ gen_op_check_subfo_64();
+}
+#endif
+GEN_INT_ARITH2_64 (subf, 0x1F, 0x08, 0x01, PPC_INTEGER);
/* subfc subfc. subfco subfco. */
-GEN_INT_ARITH2 (subfc, 0x1F, 0x08, 0x00);
+static inline void gen_op_subfc (void)
+{
+ gen_op_subf();
+ gen_op_check_subfc();
+}
+static inline void gen_op_subfco (void)
+{
+ gen_op_move_T2_T0();
+ gen_op_subf();
+ gen_op_check_subfc();
+ gen_op_check_subfo();
+}
+#if defined(TARGET_PPC64)
+static inline void gen_op_subfc_64 (void)
+{
+ gen_op_subf();
+ gen_op_check_subfc_64();
+}
+static inline void gen_op_subfco_64 (void)
+{
+ gen_op_move_T2_T0();
+ gen_op_subf();
+ gen_op_check_subfc_64();
+ gen_op_check_subfo_64();
+}
+#endif
+GEN_INT_ARITH2_64 (subfc, 0x1F, 0x08, 0x00, PPC_INTEGER);
/* subfe subfe. subfeo subfeo. */
-GEN_INT_ARITH2 (subfe, 0x1F, 0x08, 0x04);
+static inline void gen_op_subfeo (void)
+{
+ gen_op_move_T2_T0();
+ gen_op_subfe();
+ gen_op_check_subfo();
+}
+#if defined(TARGET_PPC64)
+#define gen_op_subfe_64 gen_op_subfe
+static inline void gen_op_subfeo_64 (void)
+{
+ gen_op_move_T2_T0();
+ gen_op_subfe_64();
+ gen_op_check_subfo_64();
+}
+#endif
+GEN_INT_ARITH2_64 (subfe, 0x1F, 0x08, 0x04, PPC_INTEGER);
/* subfme subfme. subfmeo subfmeo. */
-GEN_INT_ARITH1 (subfme, 0x1F, 0x08, 0x07);
+GEN_INT_ARITH1_64 (subfme, 0x1F, 0x08, 0x07, PPC_INTEGER);
/* subfze subfze. subfzeo subfzeo. */
-GEN_INT_ARITH1 (subfze, 0x1F, 0x08, 0x06);
+GEN_INT_ARITH1_64 (subfze, 0x1F, 0x08, 0x06, PPC_INTEGER);
/* addi */
GEN_HANDLER(addi, 0x0E, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
- int32_t simm = SIMM(ctx->opcode);
+ target_long simm = SIMM(ctx->opcode);
if (rA(ctx->opcode) == 0) {
- gen_op_set_T0(simm);
+ /* li case */
+ gen_set_T0(simm);
} else {
gen_op_load_gpr_T0(rA(ctx->opcode));
- gen_op_addi(simm);
+ if (likely(simm != 0))
+ gen_op_addi(simm);
}
gen_op_store_T0_gpr(rD(ctx->opcode));
}
/* addic */
GEN_HANDLER(addic, 0x0C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
+ target_long simm = SIMM(ctx->opcode);
+
gen_op_load_gpr_T0(rA(ctx->opcode));
- gen_op_addic(SIMM(ctx->opcode));
+ if (likely(simm != 0)) {
+ gen_op_move_T2_T0();
+ gen_op_addi(simm);
+#if defined(TARGET_PPC64)
+ if (ctx->sf_mode)
+ gen_op_check_addc_64();
+ else
+#endif
+ gen_op_check_addc();
+ } else {
+ gen_op_clear_xer_ca();
+ }
gen_op_store_T0_gpr(rD(ctx->opcode));
}
/* addic. */
GEN_HANDLER(addic_, 0x0D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
+ target_long simm = SIMM(ctx->opcode);
+
gen_op_load_gpr_T0(rA(ctx->opcode));
- gen_op_addic(SIMM(ctx->opcode));
- gen_op_set_Rc0();
+ if (likely(simm != 0)) {
+ gen_op_move_T2_T0();
+ gen_op_addi(simm);
+#if defined(TARGET_PPC64)
+ if (ctx->sf_mode)
+ gen_op_check_addc_64();
+ else
+#endif
+ gen_op_check_addc();
+ }
gen_op_store_T0_gpr(rD(ctx->opcode));
+ gen_set_Rc0(ctx);
}
/* addis */
GEN_HANDLER(addis, 0x0F, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
- int32_t simm = SIMM(ctx->opcode);
+ target_long simm = SIMM(ctx->opcode);
if (rA(ctx->opcode) == 0) {
- gen_op_set_T0(simm << 16);
+ /* lis case */
+ gen_set_T0(simm << 16);
} else {
gen_op_load_gpr_T0(rA(ctx->opcode));
- gen_op_addi(simm << 16);
+ if (likely(simm != 0))
+ gen_op_addi(simm << 16);
}
gen_op_store_T0_gpr(rD(ctx->opcode));
}
@@ -503,113 +832,184 @@
GEN_HANDLER(subfic, 0x08, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
gen_op_load_gpr_T0(rA(ctx->opcode));
- gen_op_subfic(SIMM(ctx->opcode));
+#if defined(TARGET_PPC64)
+ if (ctx->sf_mode)
+ gen_op_subfic_64(SIMM(ctx->opcode));
+ else
+#endif
+ gen_op_subfic(SIMM(ctx->opcode));
gen_op_store_T0_gpr(rD(ctx->opcode));
}
+#if defined(TARGET_PPC64)
+/* mulhd mulhd. */
+GEN_INT_ARITHN (mulhd, 0x1F, 0x09, 0x02, PPC_INTEGER);
+/* mulhdu mulhdu. */
+GEN_INT_ARITHN (mulhdu, 0x1F, 0x09, 0x00, PPC_INTEGER);
+/* mulld mulld. mulldo mulldo. */
+GEN_INT_ARITH2 (mulld, 0x1F, 0x09, 0x07, PPC_INTEGER);
+/* divd divd. divdo divdo. */
+GEN_INT_ARITH2 (divd, 0x1F, 0x09, 0x0F, PPC_INTEGER);
+/* divdu divdu. divduo divduo. */
+GEN_INT_ARITH2 (divdu, 0x1F, 0x09, 0x0E, PPC_INTEGER);
+#endif
+
/*** Integer comparison ***/
-#define GEN_CMP(name, opc) \
-GEN_HANDLER(name, 0x1F, 0x00, opc, 0x00400000, PPC_INTEGER) \
+#if defined(TARGET_PPC64)
+#define GEN_CMP(name, opc, type) \
+GEN_HANDLER(name, 0x1F, 0x00, opc, 0x00400000, type) \
{ \
gen_op_load_gpr_T0(rA(ctx->opcode)); \
gen_op_load_gpr_T1(rB(ctx->opcode)); \
+ if (ctx->sf_mode) \
+ gen_op_##name##_64(); \
+ else \
+ gen_op_##name(); \
+ gen_op_store_T0_crf(crfD(ctx->opcode)); \
+}
+#else
+#define GEN_CMP(name, opc, type) \
+GEN_HANDLER(name, 0x1F, 0x00, opc, 0x00400000, type) \
+{ \
+ gen_op_load_gpr_T0(rA(ctx->opcode)); \
+ gen_op_load_gpr_T1(rB(ctx->opcode)); \
gen_op_##name(); \
gen_op_store_T0_crf(crfD(ctx->opcode)); \
}
+#endif
/* cmp */
-GEN_CMP(cmp, 0x00);
+GEN_CMP(cmp, 0x00, PPC_INTEGER);
/* cmpi */
GEN_HANDLER(cmpi, 0x0B, 0xFF, 0xFF, 0x00400000, PPC_INTEGER)
{
gen_op_load_gpr_T0(rA(ctx->opcode));
- gen_op_cmpi(SIMM(ctx->opcode));
+#if defined(TARGET_PPC64)
+ if (ctx->sf_mode)
+ gen_op_cmpi_64(SIMM(ctx->opcode));
+ else
+#endif
+ gen_op_cmpi(SIMM(ctx->opcode));
gen_op_store_T0_crf(crfD(ctx->opcode));
}
/* cmpl */
-GEN_CMP(cmpl, 0x01);
+GEN_CMP(cmpl, 0x01, PPC_INTEGER);
/* cmpli */
GEN_HANDLER(cmpli, 0x0A, 0xFF, 0xFF, 0x00400000, PPC_INTEGER)
{
gen_op_load_gpr_T0(rA(ctx->opcode));
- gen_op_cmpli(UIMM(ctx->opcode));
+#if defined(TARGET_PPC64)
+ if (ctx->sf_mode)
+ gen_op_cmpli_64(UIMM(ctx->opcode));
+ else
+#endif
+ gen_op_cmpli(UIMM(ctx->opcode));
gen_op_store_T0_crf(crfD(ctx->opcode));
}
+/* isel (PowerPC 2.03 specification) */
+GEN_HANDLER(isel, 0x1F, 0x0F, 0x00, 0x00000001, PPC_203)
+{
+ uint32_t bi = rC(ctx->opcode);
+ uint32_t mask;
+
+ if (rA(ctx->opcode) == 0) {
+ gen_set_T0(0);
+ } else {
+ gen_op_load_gpr_T1(rA(ctx->opcode));
+ }
+ gen_op_load_gpr_T2(rB(ctx->opcode));
+ mask = 1 << (3 - (bi & 0x03));
+ gen_op_load_crf_T0(bi >> 2);
+ gen_op_test_true(mask);
+ gen_op_isel();
+ gen_op_store_T0_gpr(rD(ctx->opcode));
+}
+
/*** Integer logical ***/
-#define __GEN_LOGICAL2(name, opc2, opc3) \
-GEN_HANDLER(name, 0x1F, opc2, opc3, 0x00000000, PPC_INTEGER) \
+#define __GEN_LOGICAL2(name, opc2, opc3, type) \
+GEN_HANDLER(name, 0x1F, opc2, opc3, 0x00000000, type) \
{ \
gen_op_load_gpr_T0(rS(ctx->opcode)); \
gen_op_load_gpr_T1(rB(ctx->opcode)); \
gen_op_##name(); \
- if (Rc(ctx->opcode) != 0) \
- gen_op_set_Rc0(); \
gen_op_store_T0_gpr(rA(ctx->opcode)); \
+ if (unlikely(Rc(ctx->opcode) != 0)) \
+ gen_set_Rc0(ctx); \
}
-#define GEN_LOGICAL2(name, opc) \
-__GEN_LOGICAL2(name, 0x1C, opc)
+#define GEN_LOGICAL2(name, opc, type) \
+__GEN_LOGICAL2(name, 0x1C, opc, type)
-#define GEN_LOGICAL1(name, opc) \
-GEN_HANDLER(name, 0x1F, 0x1A, opc, 0x00000000, PPC_INTEGER) \
+#define GEN_LOGICAL1(name, opc, type) \
+GEN_HANDLER(name, 0x1F, 0x1A, opc, 0x00000000, type) \
{ \
gen_op_load_gpr_T0(rS(ctx->opcode)); \
gen_op_##name(); \
- if (Rc(ctx->opcode) != 0) \
- gen_op_set_Rc0(); \
gen_op_store_T0_gpr(rA(ctx->opcode)); \
+ if (unlikely(Rc(ctx->opcode) != 0)) \
+ gen_set_Rc0(ctx); \
}
/* and & and. */
-GEN_LOGICAL2(and, 0x00);
+GEN_LOGICAL2(and, 0x00, PPC_INTEGER);
/* andc & andc. */
-GEN_LOGICAL2(andc, 0x01);
+GEN_LOGICAL2(andc, 0x01, PPC_INTEGER);
/* andi. */
GEN_HANDLER(andi_, 0x1C, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
gen_op_load_gpr_T0(rS(ctx->opcode));
- gen_op_andi_(UIMM(ctx->opcode));
- gen_op_set_Rc0();
+ gen_op_andi_T0(UIMM(ctx->opcode));
gen_op_store_T0_gpr(rA(ctx->opcode));
+ gen_set_Rc0(ctx);
}
/* andis. */
GEN_HANDLER(andis_, 0x1D, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
gen_op_load_gpr_T0(rS(ctx->opcode));
- gen_op_andi_(UIMM(ctx->opcode) << 16);
- gen_op_set_Rc0();
+ gen_op_andi_T0(UIMM(ctx->opcode) << 16);
gen_op_store_T0_gpr(rA(ctx->opcode));
+ gen_set_Rc0(ctx);
}
/* cntlzw */
-GEN_LOGICAL1(cntlzw, 0x00);
+GEN_LOGICAL1(cntlzw, 0x00, PPC_INTEGER);
/* eqv & eqv. */
-GEN_LOGICAL2(eqv, 0x08);
+GEN_LOGICAL2(eqv, 0x08, PPC_INTEGER);
/* extsb & extsb. */
-GEN_LOGICAL1(extsb, 0x1D);
+GEN_LOGICAL1(extsb, 0x1D, PPC_INTEGER);
/* extsh & extsh. */
-GEN_LOGICAL1(extsh, 0x1C);
+GEN_LOGICAL1(extsh, 0x1C, PPC_INTEGER);
/* nand & nand. */
-GEN_LOGICAL2(nand, 0x0E);
+GEN_LOGICAL2(nand, 0x0E, PPC_INTEGER);
/* nor & nor. */
-GEN_LOGICAL2(nor, 0x03);
+GEN_LOGICAL2(nor, 0x03, PPC_INTEGER);
/* or & or. */
GEN_HANDLER(or, 0x1F, 0x1C, 0x0D, 0x00000000, PPC_INTEGER)
{
- gen_op_load_gpr_T0(rS(ctx->opcode));
- /* Optimisation for mr case */
- if (rS(ctx->opcode) != rB(ctx->opcode)) {
- gen_op_load_gpr_T1(rB(ctx->opcode));
- gen_op_or();
+ int rs, ra, rb;
+
+ rs = rS(ctx->opcode);
+ ra = rA(ctx->opcode);
+ rb = rB(ctx->opcode);
+ /* Optimisation for mr. ri case */
+ if (rs != ra || rs != rb) {
+ gen_op_load_gpr_T0(rs);
+ if (rs != rb) {
+ gen_op_load_gpr_T1(rb);
+ gen_op_or();
+ }
+ gen_op_store_T0_gpr(ra);
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+ } else if (unlikely(Rc(ctx->opcode) != 0)) {
+ gen_op_load_gpr_T0(rs);
+ gen_set_Rc0(ctx);
}
- if (Rc(ctx->opcode) != 0)
- gen_op_set_Rc0();
- gen_op_store_T0_gpr(rA(ctx->opcode));
}
/* orc & orc. */
-GEN_LOGICAL2(orc, 0x0C);
+GEN_LOGICAL2(orc, 0x0C, PPC_INTEGER);
/* xor & xor. */
GEN_HANDLER(xor, 0x1F, 0x1C, 0x09, 0x00000000, PPC_INTEGER)
{
@@ -619,84 +1019,129 @@
gen_op_load_gpr_T1(rB(ctx->opcode));
gen_op_xor();
} else {
- gen_op_set_T0(0);
+ gen_op_reset_T0();
}
- if (Rc(ctx->opcode) != 0)
- gen_op_set_Rc0();
gen_op_store_T0_gpr(rA(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
}
/* ori */
GEN_HANDLER(ori, 0x18, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
- uint32_t uimm = UIMM(ctx->opcode);
+ target_ulong uimm = UIMM(ctx->opcode);
if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) {
/* NOP */
+ /* XXX: should handle special NOPs for POWER series */
return;
- }
- gen_op_load_gpr_T0(rS(ctx->opcode));
- if (uimm != 0)
+ }
+ gen_op_load_gpr_T0(rS(ctx->opcode));
+ if (likely(uimm != 0))
gen_op_ori(uimm);
- gen_op_store_T0_gpr(rA(ctx->opcode));
+ gen_op_store_T0_gpr(rA(ctx->opcode));
}
/* oris */
GEN_HANDLER(oris, 0x19, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
- uint32_t uimm = UIMM(ctx->opcode);
+ target_ulong uimm = UIMM(ctx->opcode);
if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) {
/* NOP */
return;
- }
- gen_op_load_gpr_T0(rS(ctx->opcode));
- if (uimm != 0)
+ }
+ gen_op_load_gpr_T0(rS(ctx->opcode));
+ if (likely(uimm != 0))
gen_op_ori(uimm << 16);
- gen_op_store_T0_gpr(rA(ctx->opcode));
+ gen_op_store_T0_gpr(rA(ctx->opcode));
}
/* xori */
GEN_HANDLER(xori, 0x1A, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
- uint32_t uimm = UIMM(ctx->opcode);
+ target_ulong uimm = UIMM(ctx->opcode);
if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) {
/* NOP */
return;
}
gen_op_load_gpr_T0(rS(ctx->opcode));
- if (uimm != 0)
- gen_op_xori(uimm);
+ if (likely(uimm != 0))
+ gen_op_xori(uimm);
gen_op_store_T0_gpr(rA(ctx->opcode));
}
/* xoris */
GEN_HANDLER(xoris, 0x1B, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
- uint32_t uimm = UIMM(ctx->opcode);
+ target_ulong uimm = UIMM(ctx->opcode);
if (rS(ctx->opcode) == rA(ctx->opcode) && uimm == 0) {
/* NOP */
return;
}
gen_op_load_gpr_T0(rS(ctx->opcode));
- if (uimm != 0)
- gen_op_xori(uimm << 16);
+ if (likely(uimm != 0))
+ gen_op_xori(uimm << 16);
gen_op_store_T0_gpr(rA(ctx->opcode));
}
+/* popcntb : PowerPC 2.03 specification */
+GEN_HANDLER(popcntb, 0x1F, 0x03, 0x03, 0x0000F801, PPC_203)
+{
+ gen_op_load_gpr_T0(rS(ctx->opcode));
+#if defined(TARGET_PPC64)
+ if (ctx->sf_mode)
+ gen_op_popcntb_64();
+ else
+#endif
+ gen_op_popcntb();
+ gen_op_store_T0_gpr(rA(ctx->opcode));
+}
+
+#if defined(TARGET_PPC64)
+/* extsw & extsw. */
+GEN_LOGICAL1(extsw, 0x1E, PPC_64B);
+/* cntlzd */
+GEN_LOGICAL1(cntlzd, 0x01, PPC_64B);
+#endif
+
/*** Integer rotate ***/
/* rlwimi & rlwimi. */
GEN_HANDLER(rlwimi, 0x14, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
- uint32_t mb, me;
+ target_ulong mask;
+ uint32_t mb, me, sh;
mb = MB(ctx->opcode);
me = ME(ctx->opcode);
+ sh = SH(ctx->opcode);
+ if (likely(sh == 0)) {
+ if (likely(mb == 0 && me == 31)) {
+ gen_op_load_gpr_T0(rS(ctx->opcode));
+ goto do_store;
+ } else if (likely(mb == 31 && me == 0)) {
+ gen_op_load_gpr_T0(rA(ctx->opcode));
+ goto do_store;
+ }
+ gen_op_load_gpr_T0(rS(ctx->opcode));
+ gen_op_load_gpr_T1(rA(ctx->opcode));
+ goto do_mask;
+ }
gen_op_load_gpr_T0(rS(ctx->opcode));
gen_op_load_gpr_T1(rA(ctx->opcode));
- gen_op_rlwimi(SH(ctx->opcode), MASK(mb, me), ~MASK(mb, me));
- if (Rc(ctx->opcode) != 0)
- gen_op_set_Rc0();
+ gen_op_rotli32_T0(SH(ctx->opcode));
+ do_mask:
+#if defined(TARGET_PPC64)
+ mb += 32;
+ me += 32;
+#endif
+ mask = MASK(mb, me);
+ gen_op_andi_T0(mask);
+ gen_op_andi_T1(~mask);
+ gen_op_or();
+ do_store:
gen_op_store_T0_gpr(rA(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
}
/* rlwinm & rlwinm. */
GEN_HANDLER(rlwinm, 0x15, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
@@ -707,35 +1152,34 @@
mb = MB(ctx->opcode);
me = ME(ctx->opcode);
gen_op_load_gpr_T0(rS(ctx->opcode));
-#if 1 // TRY
- if (sh == 0) {
- gen_op_andi_(MASK(mb, me));
- goto store;
+ if (likely(sh == 0)) {
+ goto do_mask;
}
-#endif
- if (mb == 0) {
- if (me == 31) {
- gen_op_rotlwi(sh);
- goto store;
-#if 0
- } else if (me == (31 - sh)) {
- gen_op_slwi(sh);
- goto store;
-#endif
+ if (likely(mb == 0)) {
+ if (likely(me == 31)) {
+ gen_op_rotli32_T0(sh);
+ goto do_store;
+ } else if (likely(me == (31 - sh))) {
+ gen_op_sli_T0(sh);
+ goto do_store;
}
- } else if (me == 31) {
-#if 0
- if (sh == (32 - mb)) {
- gen_op_srwi(mb);
- goto store;
+ } else if (likely(me == 31)) {
+ if (likely(sh == (32 - mb))) {
+ gen_op_srli_T0(mb);
+ goto do_store;
}
+ }
+ gen_op_rotli32_T0(sh);
+ do_mask:
+#if defined(TARGET_PPC64)
+ mb += 32;
+ me += 32;
#endif
- }
- gen_op_rlwinm(sh, MASK(mb, me));
-store:
- if (Rc(ctx->opcode) != 0)
- gen_op_set_Rc0();
+ gen_op_andi_T0(MASK(mb, me));
+ do_store:
gen_op_store_T0_gpr(rA(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
}
/* rlwnm & rlwnm. */
GEN_HANDLER(rlwnm, 0x17, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
@@ -746,40 +1190,242 @@
me = ME(ctx->opcode);
gen_op_load_gpr_T0(rS(ctx->opcode));
gen_op_load_gpr_T1(rB(ctx->opcode));
- if (mb == 0 && me == 31) {
- gen_op_rotl();
- } else
- {
- gen_op_rlwnm(MASK(mb, me));
+ gen_op_rotl32_T0_T1();
+ if (unlikely(mb != 0 || me != 31)) {
+#if defined(TARGET_PPC64)
+ mb += 32;
+ me += 32;
+#endif
+ gen_op_andi_T0(MASK(mb, me));
}
- if (Rc(ctx->opcode) != 0)
- gen_op_set_Rc0();
gen_op_store_T0_gpr(rA(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
}
+#if defined(TARGET_PPC64)
+#define GEN_PPC64_R2(name, opc1, opc2) \
+GEN_HANDLER(name##0, opc1, opc2, 0xFF, 0x00000000, PPC_64B) \
+{ \
+ gen_##name(ctx, 0); \
+} \
+GEN_HANDLER(name##1, opc1, opc2 | 0x10, 0xFF, 0x00000000, PPC_64B) \
+{ \
+ gen_##name(ctx, 1); \
+}
+#define GEN_PPC64_R4(name, opc1, opc2) \
+GEN_HANDLER(name##0, opc1, opc2, 0xFF, 0x00000000, PPC_64B) \
+{ \
+ gen_##name(ctx, 0, 0); \
+} \
+GEN_HANDLER(name##1, opc1, opc2 | 0x01, 0xFF, 0x00000000, PPC_64B) \
+{ \
+ gen_##name(ctx, 0, 1); \
+} \
+GEN_HANDLER(name##2, opc1, opc2 | 0x10, 0xFF, 0x00000000, PPC_64B) \
+{ \
+ gen_##name(ctx, 1, 0); \
+} \
+GEN_HANDLER(name##3, opc1, opc2 | 0x11, 0xFF, 0x00000000, PPC_64B) \
+{ \
+ gen_##name(ctx, 1, 1); \
+}
+
+static inline void gen_rldinm (DisasContext *ctx, uint32_t mb, uint32_t me,
+ uint32_t sh)
+{
+ gen_op_load_gpr_T0(rS(ctx->opcode));
+ if (likely(sh == 0)) {
+ goto do_mask;
+ }
+ if (likely(mb == 0)) {
+ if (likely(me == 63)) {
+ gen_op_rotli32_T0(sh);
+ goto do_store;
+ } else if (likely(me == (63 - sh))) {
+ gen_op_sli_T0(sh);
+ goto do_store;
+ }
+ } else if (likely(me == 63)) {
+ if (likely(sh == (64 - mb))) {
+ gen_op_srli_T0(mb);
+ goto do_store;
+ }
+ }
+ gen_op_rotli64_T0(sh);
+ do_mask:
+ gen_op_andi_T0(MASK(mb, me));
+ do_store:
+ gen_op_store_T0_gpr(rA(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+/* rldicl - rldicl. */
+static inline void gen_rldicl (DisasContext *ctx, int mbn, int shn)
+{
+ uint32_t sh, mb;
+
+ sh = SH(ctx->opcode) | (shn << 5);
+ mb = MB(ctx->opcode) | (mbn << 5);
+ gen_rldinm(ctx, mb, 63, sh);
+}
+GEN_PPC64_R4(rldicl, 0x1E, 0x00);
+/* rldicr - rldicr. */
+static inline void gen_rldicr (DisasContext *ctx, int men, int shn)
+{
+ uint32_t sh, me;
+
+ sh = SH(ctx->opcode) | (shn << 5);
+ me = MB(ctx->opcode) | (men << 5);
+ gen_rldinm(ctx, 0, me, sh);
+}
+GEN_PPC64_R4(rldicr, 0x1E, 0x02);
+/* rldic - rldic. */
+static inline void gen_rldic (DisasContext *ctx, int mbn, int shn)
+{
+ uint32_t sh, mb;
+
+ sh = SH(ctx->opcode) | (shn << 5);
+ mb = MB(ctx->opcode) | (mbn << 5);
+ gen_rldinm(ctx, mb, 63 - sh, sh);
+}
+GEN_PPC64_R4(rldic, 0x1E, 0x04);
+
+static inline void gen_rldnm (DisasContext *ctx, uint32_t mb, uint32_t me)
+{
+ gen_op_load_gpr_T0(rS(ctx->opcode));
+ gen_op_load_gpr_T1(rB(ctx->opcode));
+ gen_op_rotl64_T0_T1();
+ if (unlikely(mb != 0 || me != 63)) {
+ gen_op_andi_T0(MASK(mb, me));
+ }
+ gen_op_store_T0_gpr(rA(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* rldcl - rldcl. */
+static inline void gen_rldcl (DisasContext *ctx, int mbn)
+{
+ uint32_t mb;
+
+ mb = MB(ctx->opcode) | (mbn << 5);
+ gen_rldnm(ctx, mb, 63);
+}
+GEN_PPC64_R2(rldcl, 0x1E, 0x08)
+/* rldcr - rldcr. */
+static inline void gen_rldcr (DisasContext *ctx, int men)
+{
+ uint32_t me;
+
+ me = MB(ctx->opcode) | (men << 5);
+ gen_rldnm(ctx, 0, me);
+}
+GEN_PPC64_R2(rldcr, 0x1E, 0x09)
+/* rldimi - rldimi. */
+static inline void gen_rldimi (DisasContext *ctx, int mbn, int shn)
+{
+ uint64_t mask;
+ uint32_t sh, mb;
+
+ sh = SH(ctx->opcode) | (shn << 5);
+ mb = MB(ctx->opcode) | (mbn << 5);
+ if (likely(sh == 0)) {
+ if (likely(mb == 0)) {
+ gen_op_load_gpr_T0(rS(ctx->opcode));
+ goto do_store;
+ } else if (likely(mb == 63)) {
+ gen_op_load_gpr_T0(rA(ctx->opcode));
+ goto do_store;
+ }
+ gen_op_load_gpr_T0(rS(ctx->opcode));
+ gen_op_load_gpr_T1(rA(ctx->opcode));
+ goto do_mask;
+ }
+ gen_op_load_gpr_T0(rS(ctx->opcode));
+ gen_op_load_gpr_T1(rA(ctx->opcode));
+ gen_op_rotli64_T0(SH(ctx->opcode));
+ do_mask:
+ mask = MASK(mb, 63 - sh);
+ gen_op_andi_T0(mask);
+ gen_op_andi_T1(~mask);
+ gen_op_or();
+ do_store:
+ gen_op_store_T0_gpr(rA(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+GEN_PPC64_R4(rldimi, 0x1E, 0x06)
+#endif
+
/*** Integer shift ***/
/* slw & slw. */
-__GEN_LOGICAL2(slw, 0x18, 0x00);
+__GEN_LOGICAL2(slw, 0x18, 0x00, PPC_INTEGER);
/* sraw & sraw. */
-__GEN_LOGICAL2(sraw, 0x18, 0x18);
+__GEN_LOGICAL2(sraw, 0x18, 0x18, PPC_INTEGER);
/* srawi & srawi. */
GEN_HANDLER(srawi, 0x1F, 0x18, 0x19, 0x00000000, PPC_INTEGER)
{
+ int mb, me;
gen_op_load_gpr_T0(rS(ctx->opcode));
- if (SH(ctx->opcode) != 0)
- gen_op_srawi(SH(ctx->opcode), MASK(32 - SH(ctx->opcode), 31));
- if (Rc(ctx->opcode) != 0)
- gen_op_set_Rc0();
+ if (SH(ctx->opcode) != 0) {
+ gen_op_move_T1_T0();
+ mb = 32 - SH(ctx->opcode);
+ me = 31;
+#if defined(TARGET_PPC64)
+ mb += 32;
+ me += 32;
+#endif
+ gen_op_srawi(SH(ctx->opcode), MASK(mb, me));
+ }
gen_op_store_T0_gpr(rA(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
}
/* srw & srw. */
-__GEN_LOGICAL2(srw, 0x18, 0x10);
+__GEN_LOGICAL2(srw, 0x18, 0x10, PPC_INTEGER);
+#if defined(TARGET_PPC64)
+/* sld & sld. */
+__GEN_LOGICAL2(sld, 0x1B, 0x00, PPC_64B);
+/* srad & srad. */
+__GEN_LOGICAL2(srad, 0x1A, 0x18, PPC_64B);
+/* sradi & sradi. */
+static inline void gen_sradi (DisasContext *ctx, int n)
+{
+ uint64_t mask;
+ int sh, mb, me;
+
+ gen_op_load_gpr_T0(rS(ctx->opcode));
+ sh = SH(ctx->opcode) + (n << 5);
+ if (sh != 0) {
+ gen_op_move_T1_T0();
+ mb = 64 - SH(ctx->opcode);
+ me = 63;
+ mask = MASK(mb, me);
+ gen_op_sradi(sh, mask >> 32, mask);
+ }
+ gen_op_store_T0_gpr(rA(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+GEN_HANDLER(sradi0, 0x1F, 0x1A, 0x19, 0x00000000, PPC_64B)
+{
+ gen_sradi(ctx, 0);
+}
+GEN_HANDLER(sradi1, 0x1F, 0x1B, 0x19, 0x00000000, PPC_64B)
+{
+ gen_sradi(ctx, 1);
+}
+/* srd & srd. */
+__GEN_LOGICAL2(srd, 0x1B, 0x10, PPC_64B);
+#endif
+
/*** Floating-Point arithmetic ***/
#define _GEN_FLOAT_ACB(name, op, op1, op2, isfloat) \
GEN_HANDLER(f##name, op1, op2, 0xFF, 0x00000000, PPC_FLOAT) \
{ \
- if (!ctx->fpu_enabled) { \
+ if (unlikely(!ctx->fpu_enabled)) { \
RET_EXCP(ctx, EXCP_NO_FP, 0); \
return; \
} \
@@ -792,7 +1438,7 @@
gen_op_frsp(); \
} \
gen_op_store_FT0_fpr(rD(ctx->opcode)); \
- if (Rc(ctx->opcode)) \
+ if (unlikely(Rc(ctx->opcode) != 0)) \
gen_op_set_Rc1(); \
}
@@ -803,7 +1449,7 @@
#define _GEN_FLOAT_AB(name, op, op1, op2, inval, isfloat) \
GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT) \
{ \
- if (!ctx->fpu_enabled) { \
+ if (unlikely(!ctx->fpu_enabled)) { \
RET_EXCP(ctx, EXCP_NO_FP, 0); \
return; \
} \
@@ -815,7 +1461,7 @@
gen_op_frsp(); \
} \
gen_op_store_FT0_fpr(rD(ctx->opcode)); \
- if (Rc(ctx->opcode)) \
+ if (unlikely(Rc(ctx->opcode) != 0)) \
gen_op_set_Rc1(); \
}
#define GEN_FLOAT_AB(name, op2, inval) \
@@ -825,7 +1471,7 @@
#define _GEN_FLOAT_AC(name, op, op1, op2, inval, isfloat) \
GEN_HANDLER(f##name, op1, op2, 0xFF, inval, PPC_FLOAT) \
{ \
- if (!ctx->fpu_enabled) { \
+ if (unlikely(!ctx->fpu_enabled)) { \
RET_EXCP(ctx, EXCP_NO_FP, 0); \
return; \
} \
@@ -837,7 +1483,7 @@
gen_op_frsp(); \
} \
gen_op_store_FT0_fpr(rD(ctx->opcode)); \
- if (Rc(ctx->opcode)) \
+ if (unlikely(Rc(ctx->opcode) != 0)) \
gen_op_set_Rc1(); \
}
#define GEN_FLOAT_AC(name, op2, inval) \
@@ -847,7 +1493,7 @@
#define GEN_FLOAT_B(name, op2, op3) \
GEN_HANDLER(f##name, 0x3F, op2, op3, 0x001F0000, PPC_FLOAT) \
{ \
- if (!ctx->fpu_enabled) { \
+ if (unlikely(!ctx->fpu_enabled)) { \
RET_EXCP(ctx, EXCP_NO_FP, 0); \
return; \
} \
@@ -855,14 +1501,14 @@
gen_op_load_fpr_FT0(rB(ctx->opcode)); \
gen_op_f##name(); \
gen_op_store_FT0_fpr(rD(ctx->opcode)); \
- if (Rc(ctx->opcode)) \
+ if (unlikely(Rc(ctx->opcode) != 0)) \
gen_op_set_Rc1(); \
}
#define GEN_FLOAT_BS(name, op1, op2) \
GEN_HANDLER(f##name, op1, op2, 0xFF, 0x001F07C0, PPC_FLOAT) \
{ \
- if (!ctx->fpu_enabled) { \
+ if (unlikely(!ctx->fpu_enabled)) { \
RET_EXCP(ctx, EXCP_NO_FP, 0); \
return; \
} \
@@ -870,7 +1516,7 @@
gen_op_load_fpr_FT0(rB(ctx->opcode)); \
gen_op_f##name(); \
gen_op_store_FT0_fpr(rD(ctx->opcode)); \
- if (Rc(ctx->opcode)) \
+ if (unlikely(Rc(ctx->opcode) != 0)) \
gen_op_set_Rc1(); \
}
@@ -881,13 +1527,13 @@
/* fmul - fmuls */
GEN_FLOAT_AC(mul, 0x19, 0x0000F800);
-/* fres */
+/* fres */ /* XXX: not in 601 */
GEN_FLOAT_BS(res, 0x3B, 0x18);
-/* frsqrte */
+/* frsqrte */ /* XXX: not in 601 */
GEN_FLOAT_BS(rsqrte, 0x3F, 0x1A);
-/* fsel */
+/* fsel */ /* XXX: not in 601 */
_GEN_FLOAT_ACB(sel, sel, 0x3F, 0x17, 0);
/* fsub - fsubs */
GEN_FLOAT_AB(sub, 0x14, 0x000007C0);
@@ -895,7 +1541,7 @@
/* fsqrt */
GEN_HANDLER(fsqrt, 0x3F, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_OPT)
{
- if (!ctx->fpu_enabled) {
+ if (unlikely(!ctx->fpu_enabled)) {
RET_EXCP(ctx, EXCP_NO_FP, 0);
return;
}
@@ -903,13 +1549,13 @@
gen_op_load_fpr_FT0(rB(ctx->opcode));
gen_op_fsqrt();
gen_op_store_FT0_fpr(rD(ctx->opcode));
- if (Rc(ctx->opcode))
+ if (unlikely(Rc(ctx->opcode) != 0))
gen_op_set_Rc1();
}
GEN_HANDLER(fsqrts, 0x3B, 0x16, 0xFF, 0x001F07C0, PPC_FLOAT_OPT)
{
- if (!ctx->fpu_enabled) {
+ if (unlikely(!ctx->fpu_enabled)) {
RET_EXCP(ctx, EXCP_NO_FP, 0);
return;
}
@@ -918,7 +1564,7 @@
gen_op_fsqrt();
gen_op_frsp();
gen_op_store_FT0_fpr(rD(ctx->opcode));
- if (Rc(ctx->opcode))
+ if (unlikely(Rc(ctx->opcode) != 0))
gen_op_set_Rc1();
}
@@ -939,12 +1585,20 @@
GEN_FLOAT_B(ctiwz, 0x0F, 0x00);
/* frsp */
GEN_FLOAT_B(rsp, 0x0C, 0x00);
+#if defined(TARGET_PPC64)
+/* fcfid */
+GEN_FLOAT_B(cfid, 0x0E, 0x1A);
+/* fctid */
+GEN_FLOAT_B(ctid, 0x0E, 0x19);
+/* fctidz */
+GEN_FLOAT_B(ctidz, 0x0F, 0x19);
+#endif
/*** Floating-Point compare ***/
/* fcmpo */
-GEN_HANDLER(fcmpo, 0x3F, 0x00, 0x00, 0x00600001, PPC_FLOAT)
+GEN_HANDLER(fcmpo, 0x3F, 0x00, 0x01, 0x00600001, PPC_FLOAT)
{
- if (!ctx->fpu_enabled) {
+ if (unlikely(!ctx->fpu_enabled)) {
RET_EXCP(ctx, EXCP_NO_FP, 0);
return;
}
@@ -956,9 +1610,9 @@
}
/* fcmpu */
-GEN_HANDLER(fcmpu, 0x3F, 0x00, 0x01, 0x00600001, PPC_FLOAT)
+GEN_HANDLER(fcmpu, 0x3F, 0x00, 0x00, 0x00600001, PPC_FLOAT)
{
- if (!ctx->fpu_enabled) {
+ if (unlikely(!ctx->fpu_enabled)) {
RET_EXCP(ctx, EXCP_NO_FP, 0);
return;
}
@@ -976,14 +1630,14 @@
/* fmr - fmr. */
GEN_HANDLER(fmr, 0x3F, 0x08, 0x02, 0x001F0000, PPC_FLOAT)
{
- if (!ctx->fpu_enabled) {
+ if (unlikely(!ctx->fpu_enabled)) {
RET_EXCP(ctx, EXCP_NO_FP, 0);
return;
}
gen_op_reset_scrfx();
gen_op_load_fpr_FT0(rB(ctx->opcode));
gen_op_store_FT0_fpr(rD(ctx->opcode));
- if (Rc(ctx->opcode))
+ if (unlikely(Rc(ctx->opcode) != 0))
gen_op_set_Rc1();
}
@@ -996,7 +1650,7 @@
/* mcrfs */
GEN_HANDLER(mcrfs, 0x3F, 0x00, 0x02, 0x0063F801, PPC_FLOAT)
{
- if (!ctx->fpu_enabled) {
+ if (unlikely(!ctx->fpu_enabled)) {
RET_EXCP(ctx, EXCP_NO_FP, 0);
return;
}
@@ -1008,13 +1662,13 @@
/* mffs */
GEN_HANDLER(mffs, 0x3F, 0x07, 0x12, 0x001FF800, PPC_FLOAT)
{
- if (!ctx->fpu_enabled) {
+ if (unlikely(!ctx->fpu_enabled)) {
RET_EXCP(ctx, EXCP_NO_FP, 0);
return;
}
gen_op_load_fpscr();
gen_op_store_FT0_fpr(rD(ctx->opcode));
- if (Rc(ctx->opcode))
+ if (unlikely(Rc(ctx->opcode) != 0))
gen_op_set_Rc1();
}
@@ -1023,15 +1677,15 @@
{
uint8_t crb;
- if (!ctx->fpu_enabled) {
+ if (unlikely(!ctx->fpu_enabled)) {
RET_EXCP(ctx, EXCP_NO_FP, 0);
return;
}
crb = crbD(ctx->opcode) >> 2;
gen_op_load_fpscr_T0(crb);
- gen_op_andi_(~(1 << (crbD(ctx->opcode) & 0x03)));
+ gen_op_andi_T0(~(1 << (crbD(ctx->opcode) & 0x03)));
gen_op_store_T0_fpscr(crb);
- if (Rc(ctx->opcode))
+ if (unlikely(Rc(ctx->opcode) != 0))
gen_op_set_Rc1();
}
@@ -1040,7 +1694,7 @@
{
uint8_t crb;
- if (!ctx->fpu_enabled) {
+ if (unlikely(!ctx->fpu_enabled)) {
RET_EXCP(ctx, EXCP_NO_FP, 0);
return;
}
@@ -1048,58 +1702,129 @@
gen_op_load_fpscr_T0(crb);
gen_op_ori(1 << (crbD(ctx->opcode) & 0x03));
gen_op_store_T0_fpscr(crb);
- if (Rc(ctx->opcode))
+ if (unlikely(Rc(ctx->opcode) != 0))
gen_op_set_Rc1();
}
/* mtfsf */
GEN_HANDLER(mtfsf, 0x3F, 0x07, 0x16, 0x02010000, PPC_FLOAT)
{
- if (!ctx->fpu_enabled) {
+ if (unlikely(!ctx->fpu_enabled)) {
RET_EXCP(ctx, EXCP_NO_FP, 0);
return;
}
gen_op_load_fpr_FT0(rB(ctx->opcode));
gen_op_store_fpscr(FM(ctx->opcode));
- if (Rc(ctx->opcode))
+ if (unlikely(Rc(ctx->opcode) != 0))
gen_op_set_Rc1();
}
/* mtfsfi */
GEN_HANDLER(mtfsfi, 0x3F, 0x06, 0x04, 0x006f0800, PPC_FLOAT)
{
- if (!ctx->fpu_enabled) {
+ if (unlikely(!ctx->fpu_enabled)) {
RET_EXCP(ctx, EXCP_NO_FP, 0);
return;
}
gen_op_store_T0_fpscri(crbD(ctx->opcode) >> 2, FPIMM(ctx->opcode));
- if (Rc(ctx->opcode))
+ if (unlikely(Rc(ctx->opcode) != 0))
gen_op_set_Rc1();
}
+/*** Addressing modes ***/
+/* Register indirect with immediate index : EA = (rA|0) + SIMM */
+static inline void gen_addr_imm_index (DisasContext *ctx, int maskl)
+{
+ target_long simm = SIMM(ctx->opcode);
+
+ if (maskl)
+ simm &= ~0x03;
+ if (rA(ctx->opcode) == 0) {
+ gen_set_T0(simm);
+ } else {
+ gen_op_load_gpr_T0(rA(ctx->opcode));
+ if (likely(simm != 0))
+ gen_op_addi(simm);
+ }
+#ifdef DEBUG_MEMORY_ACCESSES
+ gen_op_print_mem_EA();
+#endif
+}
+
+static inline void gen_addr_reg_index (DisasContext *ctx)
+{
+ if (rA(ctx->opcode) == 0) {
+ gen_op_load_gpr_T0(rB(ctx->opcode));
+ } else {
+ gen_op_load_gpr_T0(rA(ctx->opcode));
+ gen_op_load_gpr_T1(rB(ctx->opcode));
+ gen_op_add();
+ }
+#ifdef DEBUG_MEMORY_ACCESSES
+ gen_op_print_mem_EA();
+#endif
+}
+
+static inline void gen_addr_register (DisasContext *ctx)
+{
+ if (rA(ctx->opcode) == 0) {
+ gen_op_reset_T0();
+ } else {
+ gen_op_load_gpr_T0(rA(ctx->opcode));
+ }
+#ifdef DEBUG_MEMORY_ACCESSES
+ gen_op_print_mem_EA();
+#endif
+}
+
/*** Integer load ***/
#define op_ldst(name) (*gen_op_##name[ctx->mem_idx])()
#if defined(CONFIG_USER_ONLY)
+#if defined(TARGET_PPC64)
#define OP_LD_TABLE(width) \
static GenOpFunc *gen_op_l##width[] = { \
&gen_op_l##width##_raw, \
&gen_op_l##width##_le_raw, \
+ &gen_op_l##width##_64_raw, \
+ &gen_op_l##width##_le_64_raw, \
};
#define OP_ST_TABLE(width) \
static GenOpFunc *gen_op_st##width[] = { \
&gen_op_st##width##_raw, \
&gen_op_st##width##_le_raw, \
+ &gen_op_st##width##_64_raw, \
+ &gen_op_st##width##_le_64_raw, \
};
/* Byte access routine are endian safe */
+#define gen_op_stb_le_64_raw gen_op_stb_64_raw
+#define gen_op_lbz_le_64_raw gen_op_lbz_64_raw
+#else
+#define OP_LD_TABLE(width) \
+static GenOpFunc *gen_op_l##width[] = { \
+ &gen_op_l##width##_raw, \
+ &gen_op_l##width##_le_raw, \
+};
+#define OP_ST_TABLE(width) \
+static GenOpFunc *gen_op_st##width[] = { \
+ &gen_op_st##width##_raw, \
+ &gen_op_st##width##_le_raw, \
+};
+#endif
+/* Byte access routine are endian safe */
#define gen_op_stb_le_raw gen_op_stb_raw
#define gen_op_lbz_le_raw gen_op_lbz_raw
#else
+#if defined(TARGET_PPC64)
#define OP_LD_TABLE(width) \
static GenOpFunc *gen_op_l##width[] = { \
&gen_op_l##width##_user, \
&gen_op_l##width##_le_user, \
&gen_op_l##width##_kernel, \
&gen_op_l##width##_le_kernel, \
+ &gen_op_l##width##_64_user, \
+ &gen_op_l##width##_le_64_user, \
+ &gen_op_l##width##_64_kernel, \
+ &gen_op_l##width##_le_64_kernel, \
};
#define OP_ST_TABLE(width) \
static GenOpFunc *gen_op_st##width[] = { \
@@ -1107,189 +1832,270 @@
&gen_op_st##width##_le_user, \
&gen_op_st##width##_kernel, \
&gen_op_st##width##_le_kernel, \
+ &gen_op_st##width##_64_user, \
+ &gen_op_st##width##_le_64_user, \
+ &gen_op_st##width##_64_kernel, \
+ &gen_op_st##width##_le_64_kernel, \
};
/* Byte access routine are endian safe */
+#define gen_op_stb_le_64_user gen_op_stb_64_user
+#define gen_op_lbz_le_64_user gen_op_lbz_64_user
+#define gen_op_stb_le_64_kernel gen_op_stb_64_kernel
+#define gen_op_lbz_le_64_kernel gen_op_lbz_64_kernel
+#else
+#define OP_LD_TABLE(width) \
+static GenOpFunc *gen_op_l##width[] = { \
+ &gen_op_l##width##_user, \
+ &gen_op_l##width##_le_user, \
+ &gen_op_l##width##_kernel, \
+ &gen_op_l##width##_le_kernel, \
+};
+#define OP_ST_TABLE(width) \
+static GenOpFunc *gen_op_st##width[] = { \
+ &gen_op_st##width##_user, \
+ &gen_op_st##width##_le_user, \
+ &gen_op_st##width##_kernel, \
+ &gen_op_st##width##_le_kernel, \
+};
+#endif
+/* Byte access routine are endian safe */
#define gen_op_stb_le_user gen_op_stb_user
#define gen_op_lbz_le_user gen_op_lbz_user
#define gen_op_stb_le_kernel gen_op_stb_kernel
#define gen_op_lbz_le_kernel gen_op_lbz_kernel
#endif
-#define GEN_LD(width, opc) \
-GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \
+#define GEN_LD(width, opc, type) \
+GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, type) \
{ \
- uint32_t simm = SIMM(ctx->opcode); \
- if (rA(ctx->opcode) == 0) { \
- gen_op_set_T0(simm); \
- } else { \
- gen_op_load_gpr_T0(rA(ctx->opcode)); \
- if (simm != 0) \
- gen_op_addi(simm); \
- } \
+ gen_addr_imm_index(ctx, 0); \
op_ldst(l##width); \
gen_op_store_T1_gpr(rD(ctx->opcode)); \
}
-#define GEN_LDU(width, opc) \
-GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \
+#define GEN_LDU(width, opc, type) \
+GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, type) \
{ \
- uint32_t simm = SIMM(ctx->opcode); \
- if (rA(ctx->opcode) == 0 || \
- rA(ctx->opcode) == rD(ctx->opcode)) { \
+ if (unlikely(rA(ctx->opcode) == 0 || \
+ rA(ctx->opcode) == rD(ctx->opcode))) { \
RET_INVAL(ctx); \
return; \
} \
- gen_op_load_gpr_T0(rA(ctx->opcode)); \
- if (simm != 0) \
- gen_op_addi(simm); \
+ if (type == PPC_64B) \
+ gen_addr_imm_index(ctx, 1); \
+ else \
+ gen_addr_imm_index(ctx, 0); \
op_ldst(l##width); \
gen_op_store_T1_gpr(rD(ctx->opcode)); \
gen_op_store_T0_gpr(rA(ctx->opcode)); \
}
-#define GEN_LDUX(width, opc) \
-GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \
+#define GEN_LDUX(width, opc2, opc3, type) \
+GEN_HANDLER(l##width##ux, 0x1F, opc2, opc3, 0x00000001, type) \
{ \
- if (rA(ctx->opcode) == 0 || \
- rA(ctx->opcode) == rD(ctx->opcode)) { \
+ if (unlikely(rA(ctx->opcode) == 0 || \
+ rA(ctx->opcode) == rD(ctx->opcode))) { \
RET_INVAL(ctx); \
return; \
} \
- gen_op_load_gpr_T0(rA(ctx->opcode)); \
- gen_op_load_gpr_T1(rB(ctx->opcode)); \
- gen_op_add(); \
+ gen_addr_reg_index(ctx); \
op_ldst(l##width); \
gen_op_store_T1_gpr(rD(ctx->opcode)); \
gen_op_store_T0_gpr(rA(ctx->opcode)); \
}
-#define GEN_LDX(width, opc2, opc3) \
-GEN_HANDLER(l##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_INTEGER) \
+#define GEN_LDX(width, opc2, opc3, type) \
+GEN_HANDLER(l##width##x, 0x1F, opc2, opc3, 0x00000001, type) \
{ \
- if (rA(ctx->opcode) == 0) { \
- gen_op_load_gpr_T0(rB(ctx->opcode)); \
- } else { \
- gen_op_load_gpr_T0(rA(ctx->opcode)); \
- gen_op_load_gpr_T1(rB(ctx->opcode)); \
- gen_op_add(); \
- } \
+ gen_addr_reg_index(ctx); \
op_ldst(l##width); \
gen_op_store_T1_gpr(rD(ctx->opcode)); \
}
-#define GEN_LDS(width, op) \
+#define GEN_LDS(width, op, type) \
OP_LD_TABLE(width); \
-GEN_LD(width, op | 0x20); \
-GEN_LDU(width, op | 0x21); \
-GEN_LDUX(width, op | 0x01); \
-GEN_LDX(width, 0x17, op | 0x00)
+GEN_LD(width, op | 0x20, type); \
+GEN_LDU(width, op | 0x21, type); \
+GEN_LDUX(width, 0x17, op | 0x01, type); \
+GEN_LDX(width, 0x17, op | 0x00, type)
/* lbz lbzu lbzux lbzx */
-GEN_LDS(bz, 0x02);
+GEN_LDS(bz, 0x02, PPC_INTEGER);
/* lha lhau lhaux lhax */
-GEN_LDS(ha, 0x0A);
+GEN_LDS(ha, 0x0A, PPC_INTEGER);
/* lhz lhzu lhzux lhzx */
-GEN_LDS(hz, 0x08);
+GEN_LDS(hz, 0x08, PPC_INTEGER);
/* lwz lwzu lwzux lwzx */
-GEN_LDS(wz, 0x00);
+GEN_LDS(wz, 0x00, PPC_INTEGER);
+#if defined(TARGET_PPC64)
+OP_LD_TABLE(wa);
+OP_LD_TABLE(d);
+/* lwaux */
+GEN_LDUX(wa, 0x15, 0x0B, PPC_64B);
+/* lwax */
+GEN_LDX(wa, 0x15, 0x0A, PPC_64B);
+/* ldux */
+GEN_LDUX(d, 0x15, 0x01, PPC_64B);
+/* ldx */
+GEN_LDX(d, 0x15, 0x00, PPC_64B);
+GEN_HANDLER(ld, 0x3A, 0xFF, 0xFF, 0x00000000, PPC_64B)
+{
+ if (Rc(ctx->opcode)) {
+ if (unlikely(rA(ctx->opcode) == 0 ||
+ rA(ctx->opcode) == rD(ctx->opcode))) {
+ RET_INVAL(ctx);
+ return;
+ }
+ }
+ gen_addr_imm_index(ctx, 1);
+ if (ctx->opcode & 0x02) {
+ /* lwa (lwau is undefined) */
+ op_ldst(lwa);
+ } else {
+ /* ld - ldu */
+ op_ldst(ld);
+ }
+ gen_op_store_T1_gpr(rD(ctx->opcode));
+ if (Rc(ctx->opcode))
+ gen_op_store_T0_gpr(rA(ctx->opcode));
+}
+#endif
/*** Integer store ***/
-#define GEN_ST(width, opc) \
-GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \
+#define GEN_ST(width, opc, type) \
+GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, type) \
{ \
- uint32_t simm = SIMM(ctx->opcode); \
- if (rA(ctx->opcode) == 0) { \
- gen_op_set_T0(simm); \
- } else { \
- gen_op_load_gpr_T0(rA(ctx->opcode)); \
- if (simm != 0) \
- gen_op_addi(simm); \
- } \
+ gen_addr_imm_index(ctx, 0); \
gen_op_load_gpr_T1(rS(ctx->opcode)); \
op_ldst(st##width); \
}
-#define GEN_STU(width, opc) \
-GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_INTEGER) \
+#define GEN_STU(width, opc, type) \
+GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, type) \
{ \
- uint32_t simm = SIMM(ctx->opcode); \
- if (rA(ctx->opcode) == 0) { \
+ if (unlikely(rA(ctx->opcode) == 0)) { \
RET_INVAL(ctx); \
return; \
} \
- gen_op_load_gpr_T0(rA(ctx->opcode)); \
- if (simm != 0) \
- gen_op_addi(simm); \
+ if (type == PPC_64B) \
+ gen_addr_imm_index(ctx, 1); \
+ else \
+ gen_addr_imm_index(ctx, 0); \
gen_op_load_gpr_T1(rS(ctx->opcode)); \
op_ldst(st##width); \
gen_op_store_T0_gpr(rA(ctx->opcode)); \
}
-#define GEN_STUX(width, opc) \
-GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_INTEGER) \
+#define GEN_STUX(width, opc2, opc3, type) \
+GEN_HANDLER(st##width##ux, 0x1F, opc2, opc3, 0x00000001, type) \
{ \
- if (rA(ctx->opcode) == 0) { \
+ if (unlikely(rA(ctx->opcode) == 0)) { \
RET_INVAL(ctx); \
return; \
} \
- gen_op_load_gpr_T0(rA(ctx->opcode)); \
- gen_op_load_gpr_T1(rB(ctx->opcode)); \
- gen_op_add(); \
+ gen_addr_reg_index(ctx); \
gen_op_load_gpr_T1(rS(ctx->opcode)); \
op_ldst(st##width); \
gen_op_store_T0_gpr(rA(ctx->opcode)); \
}
-#define GEN_STX(width, opc2, opc3) \
-GEN_HANDLER(st##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_INTEGER) \
+#define GEN_STX(width, opc2, opc3, type) \
+GEN_HANDLER(st##width##x, 0x1F, opc2, opc3, 0x00000001, type) \
{ \
- if (rA(ctx->opcode) == 0) { \
- gen_op_load_gpr_T0(rB(ctx->opcode)); \
- } else { \
- gen_op_load_gpr_T0(rA(ctx->opcode)); \
- gen_op_load_gpr_T1(rB(ctx->opcode)); \
- gen_op_add(); \
- } \
+ gen_addr_reg_index(ctx); \
gen_op_load_gpr_T1(rS(ctx->opcode)); \
op_ldst(st##width); \
}
-#define GEN_STS(width, op) \
+#define GEN_STS(width, op, type) \
OP_ST_TABLE(width); \
-GEN_ST(width, op | 0x20); \
-GEN_STU(width, op | 0x21); \
-GEN_STUX(width, op | 0x01); \
-GEN_STX(width, 0x17, op | 0x00)
+GEN_ST(width, op | 0x20, type); \
+GEN_STU(width, op | 0x21, type); \
+GEN_STUX(width, 0x17, op | 0x01, type); \
+GEN_STX(width, 0x17, op | 0x00, type)
/* stb stbu stbux stbx */
-GEN_STS(b, 0x06);
+GEN_STS(b, 0x06, PPC_INTEGER);
/* sth sthu sthux sthx */
-GEN_STS(h, 0x0C);
+GEN_STS(h, 0x0C, PPC_INTEGER);
/* stw stwu stwux stwx */
-GEN_STS(w, 0x04);
-
+GEN_STS(w, 0x04, PPC_INTEGER);
+#if defined(TARGET_PPC64)
+OP_ST_TABLE(d);
+GEN_STUX(d, 0x15, 0x05, PPC_64B);
+GEN_STX(d, 0x15, 0x04, PPC_64B);
+GEN_HANDLER(std, 0x3E, 0xFF, 0xFF, 0x00000002, PPC_64B)
+{
+ if (Rc(ctx->opcode)) {
+ if (unlikely(rA(ctx->opcode) == 0)) {
+ RET_INVAL(ctx);
+ return;
+ }
+ }
+ gen_addr_imm_index(ctx, 1);
+ gen_op_load_gpr_T1(rS(ctx->opcode));
+ op_ldst(std);
+ if (Rc(ctx->opcode))
+ gen_op_store_T0_gpr(rA(ctx->opcode));
+}
+#endif
/*** Integer load and store with byte reverse ***/
/* lhbrx */
OP_LD_TABLE(hbr);
-GEN_LDX(hbr, 0x16, 0x18);
+GEN_LDX(hbr, 0x16, 0x18, PPC_INTEGER);
/* lwbrx */
OP_LD_TABLE(wbr);
-GEN_LDX(wbr, 0x16, 0x10);
+GEN_LDX(wbr, 0x16, 0x10, PPC_INTEGER);
/* sthbrx */
OP_ST_TABLE(hbr);
-GEN_STX(hbr, 0x16, 0x1C);
+GEN_STX(hbr, 0x16, 0x1C, PPC_INTEGER);
/* stwbrx */
OP_ST_TABLE(wbr);
-GEN_STX(wbr, 0x16, 0x14);
+GEN_STX(wbr, 0x16, 0x14, PPC_INTEGER);
/*** Integer load and store multiple ***/
#define op_ldstm(name, reg) (*gen_op_##name[ctx->mem_idx])(reg)
+#if defined(TARGET_PPC64)
#if defined(CONFIG_USER_ONLY)
static GenOpFunc1 *gen_op_lmw[] = {
&gen_op_lmw_raw,
&gen_op_lmw_le_raw,
+ &gen_op_lmw_64_raw,
+ &gen_op_lmw_le_64_raw,
};
static GenOpFunc1 *gen_op_stmw[] = {
+ &gen_op_stmw_64_raw,
+ &gen_op_stmw_le_64_raw,
+};
+#else
+static GenOpFunc1 *gen_op_lmw[] = {
+ &gen_op_lmw_user,
+ &gen_op_lmw_le_user,
+ &gen_op_lmw_kernel,
+ &gen_op_lmw_le_kernel,
+ &gen_op_lmw_64_user,
+ &gen_op_lmw_le_64_user,
+ &gen_op_lmw_64_kernel,
+ &gen_op_lmw_le_64_kernel,
+};
+static GenOpFunc1 *gen_op_stmw[] = {
+ &gen_op_stmw_user,
+ &gen_op_stmw_le_user,
+ &gen_op_stmw_kernel,
+ &gen_op_stmw_le_kernel,
+ &gen_op_stmw_64_user,
+ &gen_op_stmw_le_64_user,
+ &gen_op_stmw_64_kernel,
+ &gen_op_stmw_le_64_kernel,
+};
+#endif
+#else
+#if defined(CONFIG_USER_ONLY)
+static GenOpFunc1 *gen_op_lmw[] = {
+ &gen_op_lmw_raw,
+ &gen_op_lmw_le_raw,
+};
+static GenOpFunc1 *gen_op_stmw[] = {
&gen_op_stmw_raw,
&gen_op_stmw_le_raw,
};
@@ -1307,52 +2113,48 @@
&gen_op_stmw_le_kernel,
};
#endif
+#endif
/* lmw */
GEN_HANDLER(lmw, 0x2E, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
- int simm = SIMM(ctx->opcode);
-
- if (rA(ctx->opcode) == 0) {
- gen_op_set_T0(simm);
- } else {
- gen_op_load_gpr_T0(rA(ctx->opcode));
- if (simm != 0)
- gen_op_addi(simm);
- }
+ /* NIP cannot be restored if the memory exception comes from an helper */
+ gen_update_nip(ctx, ctx->nip - 4);
+ gen_addr_imm_index(ctx, 0);
op_ldstm(lmw, rD(ctx->opcode));
}
/* stmw */
GEN_HANDLER(stmw, 0x2F, 0xFF, 0xFF, 0x00000000, PPC_INTEGER)
{
- int simm = SIMM(ctx->opcode);
-
- if (rA(ctx->opcode) == 0) {
- gen_op_set_T0(simm);
- } else {
- gen_op_load_gpr_T0(rA(ctx->opcode));
- if (simm != 0)
- gen_op_addi(simm);
- }
+ /* NIP cannot be restored if the memory exception comes from an helper */
+ gen_update_nip(ctx, ctx->nip - 4);
+ gen_addr_imm_index(ctx, 0);
op_ldstm(stmw, rS(ctx->opcode));
}
/*** Integer load and store strings ***/
#define op_ldsts(name, start) (*gen_op_##name[ctx->mem_idx])(start)
#define op_ldstsx(name, rd, ra, rb) (*gen_op_##name[ctx->mem_idx])(rd, ra, rb)
+#if defined(TARGET_PPC64)
#if defined(CONFIG_USER_ONLY)
static GenOpFunc1 *gen_op_lswi[] = {
&gen_op_lswi_raw,
&gen_op_lswi_le_raw,
+ &gen_op_lswi_64_raw,
+ &gen_op_lswi_le_64_raw,
};
static GenOpFunc3 *gen_op_lswx[] = {
&gen_op_lswx_raw,
&gen_op_lswx_le_raw,
+ &gen_op_lswx_64_raw,
+ &gen_op_lswx_le_64_raw,
};
static GenOpFunc1 *gen_op_stsw[] = {
&gen_op_stsw_raw,
&gen_op_stsw_le_raw,
+ &gen_op_stsw_64_raw,
+ &gen_op_stsw_le_64_raw,
};
#else
static GenOpFunc1 *gen_op_lswi[] = {
@@ -1360,20 +2162,67 @@
&gen_op_lswi_le_user,
&gen_op_lswi_kernel,
&gen_op_lswi_le_kernel,
+ &gen_op_lswi_64_user,
+ &gen_op_lswi_le_64_user,
+ &gen_op_lswi_64_kernel,
+ &gen_op_lswi_le_64_kernel,
};
static GenOpFunc3 *gen_op_lswx[] = {
&gen_op_lswx_user,
&gen_op_lswx_le_user,
&gen_op_lswx_kernel,
&gen_op_lswx_le_kernel,
+ &gen_op_lswx_64_user,
+ &gen_op_lswx_le_64_user,
+ &gen_op_lswx_64_kernel,
+ &gen_op_lswx_le_64_kernel,
};
static GenOpFunc1 *gen_op_stsw[] = {
&gen_op_stsw_user,
&gen_op_stsw_le_user,
&gen_op_stsw_kernel,
&gen_op_stsw_le_kernel,
+ &gen_op_stsw_64_user,
+ &gen_op_stsw_le_64_user,
+ &gen_op_stsw_64_kernel,
+ &gen_op_stsw_le_64_kernel,
};
#endif
+#else
+#if defined(CONFIG_USER_ONLY)
+static GenOpFunc1 *gen_op_lswi[] = {
+ &gen_op_lswi_raw,
+ &gen_op_lswi_le_raw,
+};
+static GenOpFunc3 *gen_op_lswx[] = {
+ &gen_op_lswx_raw,
+ &gen_op_lswx_le_raw,
+};
+static GenOpFunc1 *gen_op_stsw[] = {
+ &gen_op_stsw_raw,
+ &gen_op_stsw_le_raw,
+};
+#else
+static GenOpFunc1 *gen_op_lswi[] = {
+ &gen_op_lswi_user,
+ &gen_op_lswi_le_user,
+ &gen_op_lswi_kernel,
+ &gen_op_lswi_le_kernel,
+};
+static GenOpFunc3 *gen_op_lswx[] = {
+ &gen_op_lswx_user,
+ &gen_op_lswx_le_user,
+ &gen_op_lswx_kernel,
+ &gen_op_lswx_le_kernel,
+};
+static GenOpFunc1 *gen_op_stsw[] = {
+ &gen_op_stsw_user,
+ &gen_op_stsw_le_user,
+ &gen_op_stsw_kernel,
+ &gen_op_stsw_le_kernel,
+};
+#endif
+#endif
/* lswi */
/* PowerPC32 specification says we must generate an exception if
@@ -1391,19 +2240,16 @@
if (nb == 0)
nb = 32;
nr = nb / 4;
- if (((start + nr) > 32 && start <= ra && (start + nr - 32) > ra) ||
- ((start + nr) <= 32 && start <= ra && (start + nr) > ra)) {
+ if (unlikely(((start + nr) > 32 &&
+ start <= ra && (start + nr - 32) > ra) ||
+ ((start + nr) <= 32 && start <= ra && (start + nr) > ra))) {
RET_EXCP(ctx, EXCP_PROGRAM, EXCP_INVAL | EXCP_INVAL_LSWX);
return;
}
- if (ra == 0) {
- gen_op_set_T0(0);
- } else {
- gen_op_load_gpr_T0(ra);
- }
+ /* NIP cannot be restored if the memory exception comes from an helper */
+ gen_update_nip(ctx, ctx->nip - 4);
+ gen_addr_register(ctx);
gen_op_set_T1(nb);
- /* NIP cannot be restored if the memory exception comes from an helper */
- gen_op_update_nip((ctx)->nip - 4);
op_ldsts(lswi, start);
}
@@ -1413,17 +2259,13 @@
int ra = rA(ctx->opcode);
int rb = rB(ctx->opcode);
+ /* NIP cannot be restored if the memory exception comes from an helper */
+ gen_update_nip(ctx, ctx->nip - 4);
+ gen_addr_reg_index(ctx);
if (ra == 0) {
- gen_op_load_gpr_T0(rb);
ra = rb;
- } else {
- gen_op_load_gpr_T0(ra);
- gen_op_load_gpr_T1(rb);
- gen_op_add();
}
gen_op_load_xer_bc();
- /* NIP cannot be restored if the memory exception comes from an helper */
- gen_op_update_nip((ctx)->nip - 4);
op_ldstsx(lswx, rD(ctx->opcode), ra, rb);
}
@@ -1432,59 +2274,51 @@
{
int nb = NB(ctx->opcode);
- if (rA(ctx->opcode) == 0) {
- gen_op_set_T0(0);
- } else {
- gen_op_load_gpr_T0(rA(ctx->opcode));
- }
+ /* NIP cannot be restored if the memory exception comes from an helper */
+ gen_update_nip(ctx, ctx->nip - 4);
+ gen_addr_register(ctx);
if (nb == 0)
nb = 32;
gen_op_set_T1(nb);
- /* NIP cannot be restored if the memory exception comes from an helper */
- gen_op_update_nip((ctx)->nip - 4);
op_ldsts(stsw, rS(ctx->opcode));
}
/* stswx */
GEN_HANDLER(stswx, 0x1F, 0x15, 0x14, 0x00000001, PPC_INTEGER)
{
- int ra = rA(ctx->opcode);
-
- if (ra == 0) {
- gen_op_load_gpr_T0(rB(ctx->opcode));
- ra = rB(ctx->opcode);
- } else {
- gen_op_load_gpr_T0(ra);
- gen_op_load_gpr_T1(rB(ctx->opcode));
- gen_op_add();
- }
+ /* NIP cannot be restored if the memory exception comes from an helper */
+ gen_update_nip(ctx, ctx->nip - 4);
+ gen_addr_reg_index(ctx);
gen_op_load_xer_bc();
- /* NIP cannot be restored if the memory exception comes from an helper */
- gen_op_update_nip((ctx)->nip - 4);
op_ldsts(stsw, rS(ctx->opcode));
}
/*** Memory synchronisation ***/
/* eieio */
-GEN_HANDLER(eieio, 0x1F, 0x16, 0x1A, 0x03FF0801, PPC_MEM)
+GEN_HANDLER(eieio, 0x1F, 0x16, 0x1A, 0x03FF0801, PPC_MEM_EIEIO)
{
}
/* isync */
-GEN_HANDLER(isync, 0x13, 0x16, 0xFF, 0x03FF0801, PPC_MEM)
+GEN_HANDLER(isync, 0x13, 0x16, 0x04, 0x03FF0801, PPC_MEM)
{
}
#define op_lwarx() (*gen_op_lwarx[ctx->mem_idx])()
#define op_stwcx() (*gen_op_stwcx[ctx->mem_idx])()
+#if defined(TARGET_PPC64)
#if defined(CONFIG_USER_ONLY)
static GenOpFunc *gen_op_lwarx[] = {
&gen_op_lwarx_raw,
&gen_op_lwarx_le_raw,
+ &gen_op_lwarx_64_raw,
+ &gen_op_lwarx_le_64_raw,
};
static GenOpFunc *gen_op_stwcx[] = {
&gen_op_stwcx_raw,
&gen_op_stwcx_le_raw,
+ &gen_op_stwcx_64_raw,
+ &gen_op_stwcx_le_64_raw,
};
#else
static GenOpFunc *gen_op_lwarx[] = {
@@ -1492,25 +2326,52 @@
&gen_op_lwarx_le_user,
&gen_op_lwarx_kernel,
&gen_op_lwarx_le_kernel,
+ &gen_op_lwarx_64_user,
+ &gen_op_lwarx_le_64_user,
+ &gen_op_lwarx_64_kernel,
+ &gen_op_lwarx_le_64_kernel,
};
static GenOpFunc *gen_op_stwcx[] = {
&gen_op_stwcx_user,
&gen_op_stwcx_le_user,
&gen_op_stwcx_kernel,
&gen_op_stwcx_le_kernel,
+ &gen_op_stwcx_64_user,
+ &gen_op_stwcx_le_64_user,
+ &gen_op_stwcx_64_kernel,
+ &gen_op_stwcx_le_64_kernel,
};
#endif
+#else
+#if defined(CONFIG_USER_ONLY)
+static GenOpFunc *gen_op_lwarx[] = {
+ &gen_op_lwarx_raw,
+ &gen_op_lwarx_le_raw,
+};
+static GenOpFunc *gen_op_stwcx[] = {
+ &gen_op_stwcx_raw,
+ &gen_op_stwcx_le_raw,
+};
+#else
+static GenOpFunc *gen_op_lwarx[] = {
+ &gen_op_lwarx_user,
+ &gen_op_lwarx_le_user,
+ &gen_op_lwarx_kernel,
+ &gen_op_lwarx_le_kernel,
+};
+static GenOpFunc *gen_op_stwcx[] = {
+ &gen_op_stwcx_user,
+ &gen_op_stwcx_le_user,
+ &gen_op_stwcx_kernel,
+ &gen_op_stwcx_le_kernel,
+};
+#endif
+#endif
/* lwarx */
-GEN_HANDLER(lwarx, 0x1F, 0x14, 0xFF, 0x00000001, PPC_RES)
+GEN_HANDLER(lwarx, 0x1F, 0x14, 0x00, 0x00000001, PPC_RES)
{
- if (rA(ctx->opcode) == 0) {
- gen_op_load_gpr_T0(rB(ctx->opcode));
- } else {
- gen_op_load_gpr_T0(rA(ctx->opcode));
- gen_op_load_gpr_T1(rB(ctx->opcode));
- gen_op_add();
- }
+ gen_addr_reg_index(ctx);
op_lwarx();
gen_op_store_T1_gpr(rD(ctx->opcode));
}
@@ -1518,19 +2379,69 @@
/* stwcx. */
GEN_HANDLER(stwcx_, 0x1F, 0x16, 0x04, 0x00000000, PPC_RES)
{
- if (rA(ctx->opcode) == 0) {
- gen_op_load_gpr_T0(rB(ctx->opcode));
- } else {
- gen_op_load_gpr_T0(rA(ctx->opcode));
- gen_op_load_gpr_T1(rB(ctx->opcode));
- gen_op_add();
- }
+ gen_addr_reg_index(ctx);
gen_op_load_gpr_T1(rS(ctx->opcode));
op_stwcx();
}
+#if defined(TARGET_PPC64)
+#define op_ldarx() (*gen_op_ldarx[ctx->mem_idx])()
+#define op_stdcx() (*gen_op_stdcx[ctx->mem_idx])()
+#if defined(CONFIG_USER_ONLY)
+static GenOpFunc *gen_op_ldarx[] = {
+ &gen_op_ldarx_raw,
+ &gen_op_ldarx_le_raw,
+ &gen_op_ldarx_64_raw,
+ &gen_op_ldarx_le_64_raw,
+};
+static GenOpFunc *gen_op_stdcx[] = {
+ &gen_op_stdcx_raw,
+ &gen_op_stdcx_le_raw,
+ &gen_op_stdcx_64_raw,
+ &gen_op_stdcx_le_64_raw,
+};
+#else
+static GenOpFunc *gen_op_ldarx[] = {
+ &gen_op_ldarx_user,
+ &gen_op_ldarx_le_user,
+ &gen_op_ldarx_kernel,
+ &gen_op_ldarx_le_kernel,
+ &gen_op_ldarx_64_user,
+ &gen_op_ldarx_le_64_user,
+ &gen_op_ldarx_64_kernel,
+ &gen_op_ldarx_le_64_kernel,
+};
+static GenOpFunc *gen_op_stdcx[] = {
+ &gen_op_stdcx_user,
+ &gen_op_stdcx_le_user,
+ &gen_op_stdcx_kernel,
+ &gen_op_stdcx_le_kernel,
+ &gen_op_stdcx_64_user,
+ &gen_op_stdcx_le_64_user,
+ &gen_op_stdcx_64_kernel,
+ &gen_op_stdcx_le_64_kernel,
+};
+#endif
+
+/* ldarx */
+GEN_HANDLER(ldarx, 0x1F, 0x14, 0x02, 0x00000001, PPC_RES)
+{
+ gen_addr_reg_index(ctx);
+ op_ldarx();
+ gen_op_store_T1_gpr(rD(ctx->opcode));
+}
+
+/* stdcx. */
+GEN_HANDLER(stdcx_, 0x1F, 0x16, 0x06, 0x00000000, PPC_RES)
+{
+ gen_addr_reg_index(ctx);
+ gen_op_load_gpr_T1(rS(ctx->opcode));
+ op_stdcx();
+}
+#endif /* defined(TARGET_PPC64) */
+
/* sync */
-GEN_HANDLER(sync, 0x1F, 0x16, 0x12, 0x03FF0801, PPC_MEM)
+GEN_HANDLER(sync, 0x1F, 0x16, 0x12, 0x03FF0801, PPC_MEM_SYNC)
{
}
@@ -1538,79 +2449,59 @@
#define GEN_LDF(width, opc) \
GEN_HANDLER(l##width, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \
{ \
- uint32_t simm = SIMM(ctx->opcode); \
- if (!ctx->fpu_enabled) { \
+ if (unlikely(!ctx->fpu_enabled)) { \
RET_EXCP(ctx, EXCP_NO_FP, 0); \
return; \
} \
- if (rA(ctx->opcode) == 0) { \
- gen_op_set_T0(simm); \
- } else { \
- gen_op_load_gpr_T0(rA(ctx->opcode)); \
- if (simm != 0) \
- gen_op_addi(simm); \
- } \
+ gen_addr_imm_index(ctx, 0); \
op_ldst(l##width); \
- gen_op_store_FT1_fpr(rD(ctx->opcode)); \
+ gen_op_store_FT0_fpr(rD(ctx->opcode)); \
}
#define GEN_LDUF(width, opc) \
GEN_HANDLER(l##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \
{ \
- uint32_t simm = SIMM(ctx->opcode); \
- if (!ctx->fpu_enabled) { \
+ if (unlikely(!ctx->fpu_enabled)) { \
RET_EXCP(ctx, EXCP_NO_FP, 0); \
return; \
} \
- if (rA(ctx->opcode) == 0 || \
- rA(ctx->opcode) == rD(ctx->opcode)) { \
+ if (unlikely(rA(ctx->opcode) == 0)) { \
RET_INVAL(ctx); \
return; \
} \
- gen_op_load_gpr_T0(rA(ctx->opcode)); \
- if (simm != 0) \
- gen_op_addi(simm); \
+ gen_addr_imm_index(ctx, 0); \
op_ldst(l##width); \
- gen_op_store_FT1_fpr(rD(ctx->opcode)); \
+ gen_op_store_FT0_fpr(rD(ctx->opcode)); \
gen_op_store_T0_gpr(rA(ctx->opcode)); \
}
#define GEN_LDUXF(width, opc) \
GEN_HANDLER(l##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT) \
{ \
- if (!ctx->fpu_enabled) { \
+ if (unlikely(!ctx->fpu_enabled)) { \
RET_EXCP(ctx, EXCP_NO_FP, 0); \
return; \
} \
- if (rA(ctx->opcode) == 0 || \
- rA(ctx->opcode) == rD(ctx->opcode)) { \
+ if (unlikely(rA(ctx->opcode) == 0)) { \
RET_INVAL(ctx); \
return; \
} \
- gen_op_load_gpr_T0(rA(ctx->opcode)); \
- gen_op_load_gpr_T1(rB(ctx->opcode)); \
- gen_op_add(); \
+ gen_addr_reg_index(ctx); \
op_ldst(l##width); \
- gen_op_store_FT1_fpr(rD(ctx->opcode)); \
+ gen_op_store_FT0_fpr(rD(ctx->opcode)); \
gen_op_store_T0_gpr(rA(ctx->opcode)); \
}
#define GEN_LDXF(width, opc2, opc3) \
GEN_HANDLER(l##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_FLOAT) \
{ \
- if (!ctx->fpu_enabled) { \
+ if (unlikely(!ctx->fpu_enabled)) { \
RET_EXCP(ctx, EXCP_NO_FP, 0); \
return; \
} \
- if (rA(ctx->opcode) == 0) { \
- gen_op_load_gpr_T0(rB(ctx->opcode)); \
- } else { \
- gen_op_load_gpr_T0(rA(ctx->opcode)); \
- gen_op_load_gpr_T1(rB(ctx->opcode)); \
- gen_op_add(); \
- } \
+ gen_addr_reg_index(ctx); \
op_ldst(l##width); \
- gen_op_store_FT1_fpr(rD(ctx->opcode)); \
+ gen_op_store_FT0_fpr(rD(ctx->opcode)); \
}
#define GEN_LDFS(width, op) \
@@ -1629,38 +2520,28 @@
#define GEN_STF(width, opc) \
GEN_HANDLER(st##width, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \
{ \
- uint32_t simm = SIMM(ctx->opcode); \
- if (!ctx->fpu_enabled) { \
+ if (unlikely(!ctx->fpu_enabled)) { \
RET_EXCP(ctx, EXCP_NO_FP, 0); \
return; \
} \
- if (rA(ctx->opcode) == 0) { \
- gen_op_set_T0(simm); \
- } else { \
- gen_op_load_gpr_T0(rA(ctx->opcode)); \
- if (simm != 0) \
- gen_op_addi(simm); \
- } \
- gen_op_load_fpr_FT1(rS(ctx->opcode)); \
+ gen_addr_imm_index(ctx, 0); \
+ gen_op_load_fpr_FT0(rS(ctx->opcode)); \
op_ldst(st##width); \
}
#define GEN_STUF(width, opc) \
GEN_HANDLER(st##width##u, opc, 0xFF, 0xFF, 0x00000000, PPC_FLOAT) \
{ \
- uint32_t simm = SIMM(ctx->opcode); \
- if (!ctx->fpu_enabled) { \
+ if (unlikely(!ctx->fpu_enabled)) { \
RET_EXCP(ctx, EXCP_NO_FP, 0); \
return; \
} \
- if (rA(ctx->opcode) == 0) { \
+ if (unlikely(rA(ctx->opcode) == 0)) { \
RET_INVAL(ctx); \
return; \
} \
- gen_op_load_gpr_T0(rA(ctx->opcode)); \
- if (simm != 0) \
- gen_op_addi(simm); \
- gen_op_load_fpr_FT1(rS(ctx->opcode)); \
+ gen_addr_imm_index(ctx, 0); \
+ gen_op_load_fpr_FT0(rS(ctx->opcode)); \
op_ldst(st##width); \
gen_op_store_T0_gpr(rA(ctx->opcode)); \
}
@@ -1668,18 +2549,16 @@
#define GEN_STUXF(width, opc) \
GEN_HANDLER(st##width##ux, 0x1F, 0x17, opc, 0x00000001, PPC_FLOAT) \
{ \
- if (!ctx->fpu_enabled) { \
+ if (unlikely(!ctx->fpu_enabled)) { \
RET_EXCP(ctx, EXCP_NO_FP, 0); \
return; \
} \
- if (rA(ctx->opcode) == 0) { \
+ if (unlikely(rA(ctx->opcode) == 0)) { \
RET_INVAL(ctx); \
return; \
} \
- gen_op_load_gpr_T0(rA(ctx->opcode)); \
- gen_op_load_gpr_T1(rB(ctx->opcode)); \
- gen_op_add(); \
- gen_op_load_fpr_FT1(rS(ctx->opcode)); \
+ gen_addr_reg_index(ctx); \
+ gen_op_load_fpr_FT0(rS(ctx->opcode)); \
op_ldst(st##width); \
gen_op_store_T0_gpr(rA(ctx->opcode)); \
}
@@ -1687,18 +2566,12 @@
#define GEN_STXF(width, opc2, opc3) \
GEN_HANDLER(st##width##x, 0x1F, opc2, opc3, 0x00000001, PPC_FLOAT) \
{ \
- if (!ctx->fpu_enabled) { \
+ if (unlikely(!ctx->fpu_enabled)) { \
RET_EXCP(ctx, EXCP_NO_FP, 0); \
return; \
} \
- if (rA(ctx->opcode) == 0) { \
- gen_op_load_gpr_T0(rB(ctx->opcode)); \
- } else { \
- gen_op_load_gpr_T0(rA(ctx->opcode)); \
- gen_op_load_gpr_T1(rB(ctx->opcode)); \
- gen_op_add(); \
- } \
- gen_op_load_fpr_FT1(rS(ctx->opcode)); \
+ gen_addr_reg_index(ctx); \
+ gen_op_load_fpr_FT0(rS(ctx->opcode)); \
op_ldst(st##width); \
}
@@ -1718,10 +2591,12 @@
/* stfiwx */
GEN_HANDLER(stfiwx, 0x1F, 0x17, 0x1E, 0x00000001, PPC_FLOAT)
{
- if (!ctx->fpu_enabled) {
+ if (unlikely(!ctx->fpu_enabled)) {
RET_EXCP(ctx, EXCP_NO_FP, 0);
return;
}
+ gen_addr_reg_index(ctx);
+ /* XXX: TODO: memcpy low order 32 bits of FRP(rs) into memory */
RET_INVAL(ctx);
}
@@ -1736,18 +2611,28 @@
gen_op_goto_tb0(TBPARAM(tb));
else
gen_op_goto_tb1(TBPARAM(tb));
- gen_op_set_T1(dest);
- gen_op_b_T1();
+ gen_set_T1(dest);
+#if defined(TARGET_PPC64)
+ if (ctx->sf_mode)
+ gen_op_b_T1_64();
+ else
+#endif
+ gen_op_b_T1();
gen_op_set_T0((long)tb + n);
if (ctx->singlestep_enabled)
gen_op_debug();
gen_op_exit_tb();
} else {
- gen_op_set_T1(dest);
- gen_op_b_T1();
+ gen_set_T1(dest);
+#if defined(TARGET_PPC64)
+ if (ctx->sf_mode)
+ gen_op_b_T1_64();
+ else
+#endif
+ gen_op_b_T1();
+ gen_op_reset_T0();
if (ctx->singlestep_enabled)
gen_op_debug();
- gen_op_set_T0(0);
gen_op_exit_tb();
}
}
@@ -1755,17 +2640,26 @@
/* b ba bl bla */
GEN_HANDLER(b, 0x12, 0xFF, 0xFF, 0x00000000, PPC_FLOW)
{
- uint32_t li, target;
+ target_ulong li, target;
/* sign extend LI */
- li = ((int32_t)LI(ctx->opcode) << 6) >> 6;
-
- if (AA(ctx->opcode) == 0)
+#if defined(TARGET_PPC64)
+ if (ctx->sf_mode)
+ li = ((int64_t)LI(ctx->opcode) << 38) >> 38;
+ else
+#endif
+ li = ((int32_t)LI(ctx->opcode) << 6) >> 6;
+ if (likely(AA(ctx->opcode) == 0))
target = ctx->nip + li - 4;
else
target = li;
if (LK(ctx->opcode)) {
- gen_op_setlr(ctx->nip);
+#if defined(TARGET_PPC64)
+ if (ctx->sf_mode)
+ gen_op_setlr_64(ctx->nip >> 32, ctx->nip);
+ else
+#endif
+ gen_op_setlr(ctx->nip);
}
gen_goto_tb(ctx, 0, target);
ctx->exception = EXCP_BRANCH;
@@ -1775,20 +2669,20 @@
#define BCOND_LR 1
#define BCOND_CTR 2
-static inline void gen_bcond(DisasContext *ctx, int type)
-{
- uint32_t target = 0;
- uint32_t bo = BO(ctx->opcode);
- uint32_t bi = BI(ctx->opcode);
- uint32_t mask;
- uint32_t li;
+static inline void gen_bcond(DisasContext *ctx, int type)
+{
+ target_ulong target = 0;
+ target_ulong li;
+ uint32_t bo = BO(ctx->opcode);
+ uint32_t bi = BI(ctx->opcode);
+ uint32_t mask;
if ((bo & 0x4) == 0)
- gen_op_dec_ctr();
+ gen_op_dec_ctr();
switch(type) {
case BCOND_IM:
- li = (int32_t)((int16_t)(BD(ctx->opcode)));
- if (AA(ctx->opcode) == 0) {
+ li = (target_long)((int16_t)(BD(ctx->opcode)));
+ if (likely(AA(ctx->opcode) == 0)) {
target = ctx->nip + li - 4;
} else {
target = li;
@@ -1802,61 +2696,102 @@
gen_op_movl_T1_lr();
break;
}
- if (LK(ctx->opcode)) {
- gen_op_setlr(ctx->nip);
+ if (LK(ctx->opcode)) {
+#if defined(TARGET_PPC64)
+ if (ctx->sf_mode)
+ gen_op_setlr_64(ctx->nip >> 32, ctx->nip);
+ else
+#endif
+ gen_op_setlr(ctx->nip);
}
if (bo & 0x10) {
- /* No CR condition */
- switch (bo & 0x6) {
- case 0:
- gen_op_test_ctr();
+ /* No CR condition */
+ switch (bo & 0x6) {
+ case 0:
+#if defined(TARGET_PPC64)
+ if (ctx->sf_mode)
+ gen_op_test_ctr_64();
+ else
+#endif
+ gen_op_test_ctr();
break;
- case 2:
- gen_op_test_ctrz();
- break;
+ case 2:
+#if defined(TARGET_PPC64)
+ if (ctx->sf_mode)
+ gen_op_test_ctrz_64();
+ else
+#endif
+ gen_op_test_ctrz();
+ break;
default:
- case 4:
- case 6:
+ case 4:
+ case 6:
if (type == BCOND_IM) {
gen_goto_tb(ctx, 0, target);
} else {
- gen_op_b_T1();
+#if defined(TARGET_PPC64)
+ if (ctx->sf_mode)
+ gen_op_b_T1_64();
+ else
+#endif
+ gen_op_b_T1();
+ gen_op_reset_T0();
}
goto no_test;
}
- } else {
- mask = 1 << (3 - (bi & 0x03));
- gen_op_load_crf_T0(bi >> 2);
- if (bo & 0x8) {
- switch (bo & 0x6) {
- case 0:
- gen_op_test_ctr_true(mask);
- break;
- case 2:
- gen_op_test_ctrz_true(mask);
- break;
- default:
- case 4:
- case 6:
+ } else {
+ mask = 1 << (3 - (bi & 0x03));
+ gen_op_load_crf_T0(bi >> 2);
+ if (bo & 0x8) {
+ switch (bo & 0x6) {
+ case 0:
+#if defined(TARGET_PPC64)
+ if (ctx->sf_mode)
+ gen_op_test_ctr_true_64(mask);
+ else
+#endif
+ gen_op_test_ctr_true(mask);
+ break;
+ case 2:
+#if defined(TARGET_PPC64)
+ if (ctx->sf_mode)
+ gen_op_test_ctrz_true_64(mask);
+ else
+#endif
+ gen_op_test_ctrz_true(mask);
+ break;
+ default:
+ case 4:
+ case 6:
gen_op_test_true(mask);
- break;
- }
- } else {
- switch (bo & 0x6) {
- case 0:
- gen_op_test_ctr_false(mask);
- break;
- case 2:
- gen_op_test_ctrz_false(mask);
- break;
+ break;
+ }
+ } else {
+ switch (bo & 0x6) {
+ case 0:
+#if defined(TARGET_PPC64)
+ if (ctx->sf_mode)
+ gen_op_test_ctr_false_64(mask);
+ else
+#endif
+ gen_op_test_ctr_false(mask);
+ break;
+ case 2:
+#if defined(TARGET_PPC64)
+ if (ctx->sf_mode)
+ gen_op_test_ctrz_false_64(mask);
+ else
+#endif
+ gen_op_test_ctrz_false(mask);
+ break;
default:
- case 4:
- case 6:
+ case 4:
+ case 6:
gen_op_test_false(mask);
- break;
- }
- }
- }
+ break;
+ }
+ }
+ }
if (type == BCOND_IM) {
int l1 = gen_new_label();
gen_op_jz_T0(l1);
@@ -1864,24 +2799,33 @@
gen_set_label(l1);
gen_goto_tb(ctx, 1, ctx->nip);
} else {
- gen_op_btest_T1(ctx->nip);
+#if defined(TARGET_PPC64)
+ if (ctx->sf_mode)
+ gen_op_btest_T1_64(ctx->nip >> 32, ctx->nip);
+ else
+#endif
+ gen_op_btest_T1(ctx->nip);
+ gen_op_reset_T0();
+ no_test:
+ if (ctx->singlestep_enabled)
+ gen_op_debug();
+ gen_op_exit_tb();
}
- no_test:
- ctx->exception = EXCP_BRANCH;
+ ctx->exception = EXCP_BRANCH;
}
GEN_HANDLER(bc, 0x10, 0xFF, 0xFF, 0x00000000, PPC_FLOW)
-{
+{
gen_bcond(ctx, BCOND_IM);
}
GEN_HANDLER(bcctr, 0x13, 0x10, 0x10, 0x00000000, PPC_FLOW)
-{
+{
gen_bcond(ctx, BCOND_CTR);
}
GEN_HANDLER(bclr, 0x13, 0x10, 0x00, 0x00000000, PPC_FLOW)
-{
+{
gen_bcond(ctx, BCOND_LR);
}
@@ -1901,21 +2845,21 @@
}
/* crand */
-GEN_CRLOGIC(and, 0x08)
+GEN_CRLOGIC(and, 0x08);
/* crandc */
-GEN_CRLOGIC(andc, 0x04)
+GEN_CRLOGIC(andc, 0x04);
/* creqv */
-GEN_CRLOGIC(eqv, 0x09)
+GEN_CRLOGIC(eqv, 0x09);
/* crnand */
-GEN_CRLOGIC(nand, 0x07)
+GEN_CRLOGIC(nand, 0x07);
/* crnor */
-GEN_CRLOGIC(nor, 0x01)
+GEN_CRLOGIC(nor, 0x01);
/* cror */
-GEN_CRLOGIC(or, 0x0E)
+GEN_CRLOGIC(or, 0x0E);
/* crorc */
-GEN_CRLOGIC(orc, 0x0D)
+GEN_CRLOGIC(orc, 0x0D);
/* crxor */
-GEN_CRLOGIC(xor, 0x06)
+GEN_CRLOGIC(xor, 0x06);
/* mcrf */
GEN_HANDLER(mcrf, 0x13, 0x00, 0xFF, 0x00000001, PPC_INTEGER)
{
@@ -1925,13 +2869,13 @@
/*** System linkage ***/
/* rfi (supervisor only) */
-GEN_HANDLER(rfi, 0x13, 0x12, 0xFF, 0x03FF8001, PPC_FLOW)
+GEN_HANDLER(rfi, 0x13, 0x12, 0x01, 0x03FF8001, PPC_FLOW)
{
#if defined(CONFIG_USER_ONLY)
RET_PRIVOPC(ctx);
#else
/* Restore CPU state */
- if (!ctx->supervisor) {
+ if (unlikely(!ctx->supervisor)) {
RET_PRIVOPC(ctx);
return;
}
@@ -1940,6 +2884,23 @@
#endif
}
+#if defined(TARGET_PPC64)
+GEN_HANDLER(rfid, 0x13, 0x12, 0x00, 0x03FF8001, PPC_FLOW)
+{
+#if defined(CONFIG_USER_ONLY)
+ RET_PRIVOPC(ctx);
+#else
+ /* Restore CPU state */
+ if (unlikely(!ctx->supervisor)) {
+ RET_PRIVOPC(ctx);
+ return;
+ }
+ gen_op_rfid();
+ RET_CHG_FLOW(ctx);
+#endif
+}
+#endif
+
/* sc */
GEN_HANDLER(sc, 0x11, 0xFF, 0xFF, 0x03FFFFFD, PPC_FLOW)
{
@@ -1952,12 +2913,12 @@
/*** Trap ***/
/* tw */
-GEN_HANDLER(tw, 0x1F, 0x04, 0xFF, 0x00000001, PPC_FLOW)
+GEN_HANDLER(tw, 0x1F, 0x04, 0x00, 0x00000001, PPC_FLOW)
{
gen_op_load_gpr_T0(rA(ctx->opcode));
gen_op_load_gpr_T1(rB(ctx->opcode));
/* Update the nip since this might generate a trap exception */
- gen_op_update_nip(ctx->nip);
+ gen_update_nip(ctx, ctx->nip);
gen_op_tw(TO(ctx->opcode));
}
@@ -1965,51 +2926,58 @@
GEN_HANDLER(twi, 0x03, 0xFF, 0xFF, 0x00000000, PPC_FLOW)
{
gen_op_load_gpr_T0(rA(ctx->opcode));
-#if 0
- printf("%s: param=0x%04x T0=0x%04x\n", __func__,
- SIMM(ctx->opcode), TO(ctx->opcode));
-#endif
- gen_op_twi(SIMM(ctx->opcode), TO(ctx->opcode));
+ gen_set_T1(SIMM(ctx->opcode));
+ /* Update the nip since this might generate a trap exception */
+ gen_update_nip(ctx, ctx->nip);
+ gen_op_tw(TO(ctx->opcode));
}
-/*** Processor control ***/
-static inline int check_spr_access (int spr, int rw, int supervisor)
+#if defined(TARGET_PPC64)
+/* td */
+GEN_HANDLER(td, 0x1F, 0x04, 0x02, 0x00000001, PPC_64B)
{
- uint32_t rights = spr_access[spr >> 1] >> (4 * (spr & 1));
+ gen_op_load_gpr_T0(rA(ctx->opcode));
+ gen_op_load_gpr_T1(rB(ctx->opcode));
+ /* Update the nip since this might generate a trap exception */
+ gen_update_nip(ctx, ctx->nip);
+ gen_op_td(TO(ctx->opcode));
+}
-#if 0
- if (spr != LR && spr != CTR) {
- if (loglevel > 0) {
- fprintf(logfile, "%s reg=%d s=%d rw=%d r=0x%02x 0x%02x\n", __func__,
- SPR_ENCODE(spr), supervisor, rw, rights,
- (rights >> ((2 * supervisor) + rw)) & 1);
- } else {
- printf("%s reg=%d s=%d rw=%d r=0x%02x 0x%02x\n", __func__,
- SPR_ENCODE(spr), supervisor, rw, rights,
- (rights >> ((2 * supervisor) + rw)) & 1);
- }
- }
+/* tdi */
+GEN_HANDLER(tdi, 0x02, 0xFF, 0xFF, 0x00000000, PPC_64B)
+{
+ gen_op_load_gpr_T0(rA(ctx->opcode));
+ gen_set_T1(SIMM(ctx->opcode));
+ /* Update the nip since this might generate a trap exception */
+ gen_update_nip(ctx, ctx->nip);
+ gen_op_td(TO(ctx->opcode));
+}
#endif
- if (rights == 0)
- return -1;
- rights = rights >> (2 * supervisor);
- rights = rights >> rw;
- return rights & 1;
-}
-
+/*** Processor control ***/
/* mcrxr */
GEN_HANDLER(mcrxr, 0x1F, 0x00, 0x10, 0x007FF801, PPC_MISC)
{
gen_op_load_xer_cr();
gen_op_store_T0_crf(crfD(ctx->opcode));
- gen_op_clear_xer_cr();
+ gen_op_clear_xer_ov();
+ gen_op_clear_xer_ca();
}
/* mfcr */
-GEN_HANDLER(mfcr, 0x1F, 0x13, 0x00, 0x001FF801, PPC_MISC)
+GEN_HANDLER(mfcr, 0x1F, 0x13, 0x00, 0x00000801, PPC_MISC)
{
- gen_op_load_cr();
+ uint32_t crm, crn;
+
+ if (likely(ctx->opcode & 0x00100000)) {
+ crm = CRM(ctx->opcode);
+ if (likely((crm ^ (crm - 1)) == 0)) {
+ crn = ffs(crm);
+ gen_op_load_cro(7 - crn);
+ }
+ } else {
+ gen_op_load_cr();
+ }
gen_op_store_T0_gpr(rD(ctx->opcode));
}
@@ -2019,7 +2987,7 @@
#if defined(CONFIG_USER_ONLY)
RET_PRIVREG(ctx);
#else
- if (!ctx->supervisor) {
+ if (unlikely(!ctx->supervisor)) {
RET_PRIVREG(ctx);
return;
}
@@ -2051,22 +3019,22 @@
else
#endif
read_cb = ctx->spr_cb[sprn].uea_read;
- if (read_cb != NULL) {
- if (read_cb != SPR_NOACCESS) {
+ if (likely(read_cb != NULL)) {
+ if (likely(read_cb != SPR_NOACCESS)) {
(*read_cb)(ctx, sprn);
gen_op_store_T0_gpr(rD(ctx->opcode));
} else {
/* Privilege exception */
- if (loglevel) {
+ if (loglevel != 0) {
fprintf(logfile, "Trying to read priviledged spr %d %03x\n",
sprn, sprn);
}
printf("Trying to read priviledged spr %d %03x\n", sprn, sprn);
- RET_PRIVREG(ctx);
+ RET_PRIVREG(ctx);
}
} else {
/* Not defined */
- if (loglevel) {
+ if (loglevel != 0) {
fprintf(logfile, "Trying to read invalid spr %d %03x\n",
sprn, sprn);
}
@@ -2078,7 +3046,7 @@
GEN_HANDLER(mfspr, 0x1F, 0x13, 0x0A, 0x00000001, PPC_MISC)
{
gen_op_mfspr(ctx);
- }
+}
/* mftb */
GEN_HANDLER(mftb, 0x1F, 0x13, 0x0B, 0x00000001, PPC_TB)
@@ -2087,31 +3055,64 @@
}
/* mtcrf */
-/* The mask should be 0x00100801, but Mac OS X 10.4 use an alternate form */
GEN_HANDLER(mtcrf, 0x1F, 0x10, 0x04, 0x00000801, PPC_MISC)
{
+ uint32_t crm, crn;
+
gen_op_load_gpr_T0(rS(ctx->opcode));
- gen_op_store_cr(CRM(ctx->opcode));
+ crm = CRM(ctx->opcode);
+ if (likely((ctx->opcode & 0x00100000) || (crm ^ (crm - 1)) == 0)) {
+ crn = ffs(crm);
+ gen_op_srli_T0(crn * 4);
+ gen_op_andi_T0(0xF);
+ gen_op_store_cro(7 - crn);
+ } else {
+ gen_op_store_cr(crm);
+ }
}
/* mtmsr */
-GEN_HANDLER(mtmsr, 0x1F, 0x12, 0x04, 0x001FF801, PPC_MISC)
+#if defined(TARGET_PPC64)
+GEN_HANDLER(mtmsrd, 0x1F, 0x12, 0x05, 0x001FF801, PPC_MISC)
{
#if defined(CONFIG_USER_ONLY)
RET_PRIVREG(ctx);
#else
- if (!ctx->supervisor) {
+ if (unlikely(!ctx->supervisor)) {
RET_PRIVREG(ctx);
return;
}
- gen_op_update_nip((ctx)->nip);
+ gen_update_nip(ctx, ctx->nip);
gen_op_load_gpr_T0(rS(ctx->opcode));
gen_op_store_msr();
/* Must stop the translation as machine state (may have) changed */
RET_CHG_FLOW(ctx);
#endif
}
+#endif
+GEN_HANDLER(mtmsr, 0x1F, 0x12, 0x04, 0x001FF801, PPC_MISC)
+{
+#if defined(CONFIG_USER_ONLY)
+ RET_PRIVREG(ctx);
+#else
+ if (unlikely(!ctx->supervisor)) {
+ RET_PRIVREG(ctx);
+ return;
+ }
+ gen_update_nip(ctx, ctx->nip);
+ gen_op_load_gpr_T0(rS(ctx->opcode));
+#if defined(TARGET_PPC64)
+ if (!ctx->sf_mode)
+ gen_op_store_msr_32();
+ else
+#endif
+ gen_op_store_msr();
+ /* Must stop the translation as machine state (may have) changed */
+ RET_CHG_FLOW(ctx);
+#endif
+}
+
/* mtspr */
GEN_HANDLER(mtspr, 0x1F, 0x13, 0x0E, 0x00000001, PPC_MISC)
{
@@ -2124,22 +3125,22 @@
else
#endif
write_cb = ctx->spr_cb[sprn].uea_write;
- if (write_cb != NULL) {
- if (write_cb != SPR_NOACCESS) {
+ if (likely(write_cb != NULL)) {
+ if (likely(write_cb != SPR_NOACCESS)) {
gen_op_load_gpr_T0(rS(ctx->opcode));
(*write_cb)(ctx, sprn);
} else {
/* Privilege exception */
- if (loglevel) {
+ if (loglevel != 0) {
fprintf(logfile, "Trying to write priviledged spr %d %03x\n",
sprn, sprn);
}
printf("Trying to write priviledged spr %d %03x\n", sprn, sprn);
- RET_PRIVREG(ctx);
- }
+ RET_PRIVREG(ctx);
+ }
} else {
/* Not defined */
- if (loglevel) {
+ if (loglevel != 0) {
fprintf(logfile, "Trying to write invalid spr %d %03x\n",
sprn, sprn);
}
@@ -2156,13 +3157,7 @@
/* dcbf */
GEN_HANDLER(dcbf, 0x1F, 0x16, 0x02, 0x03E00001, PPC_CACHE)
{
- if (rA(ctx->opcode) == 0) {
- gen_op_load_gpr_T0(rB(ctx->opcode));
- } else {
- gen_op_load_gpr_T0(rA(ctx->opcode));
- gen_op_load_gpr_T1(rB(ctx->opcode));
- gen_op_add();
- }
+ gen_addr_reg_index(ctx);
op_ldst(lbz);
}
@@ -2172,18 +3167,13 @@
#if defined(CONFIG_USER_ONLY)
RET_PRIVOPC(ctx);
#else
- if (!ctx->supervisor) {
+ if (unlikely(!ctx->supervisor)) {
RET_PRIVOPC(ctx);
return;
}
- if (rA(ctx->opcode) == 0) {
- gen_op_load_gpr_T0(rB(ctx->opcode));
- } else {
- gen_op_load_gpr_T0(rA(ctx->opcode));
- gen_op_load_gpr_T1(rB(ctx->opcode));
- gen_op_add();
- }
- op_ldst(lbz);
+ gen_addr_reg_index(ctx);
+ /* XXX: specification says this should be treated as a store by the MMU */
+ //op_ldst(lbz);
op_ldst(stb);
#endif
}
@@ -2191,63 +3181,116 @@
/* dcdst */
GEN_HANDLER(dcbst, 0x1F, 0x16, 0x01, 0x03E00001, PPC_CACHE)
{
- if (rA(ctx->opcode) == 0) {
- gen_op_load_gpr_T0(rB(ctx->opcode));
- } else {
- gen_op_load_gpr_T0(rA(ctx->opcode));
- gen_op_load_gpr_T1(rB(ctx->opcode));
- gen_op_add();
- }
+ /* XXX: specification say this is treated as a load by the MMU */
+ gen_addr_reg_index(ctx);
op_ldst(lbz);
}
/* dcbt */
GEN_HANDLER(dcbt, 0x1F, 0x16, 0x08, 0x03E00001, PPC_CACHE)
{
+ /* XXX: specification say this is treated as a load by the MMU
+ * but does not generate any exception
+ */
}
/* dcbtst */
GEN_HANDLER(dcbtst, 0x1F, 0x16, 0x07, 0x03E00001, PPC_CACHE)
{
+ /* XXX: specification say this is treated as a load by the MMU
+ * but does not generate any exception
+ */
}
/* dcbz */
+#define op_dcbz() (*gen_op_dcbz[ctx->mem_idx])()
+#if defined(TARGET_PPC64)
#if defined(CONFIG_USER_ONLY)
-#define op_dcbz() gen_op_dcbz_raw()
+static GenOpFunc *gen_op_dcbz[] = {
+ &gen_op_dcbz_raw,
+ &gen_op_dcbz_raw,
+ &gen_op_dcbz_64_raw,
+ &gen_op_dcbz_64_raw,
+};
#else
-#define op_dcbz() (*gen_op_dcbz[ctx->mem_idx])()
static GenOpFunc *gen_op_dcbz[] = {
&gen_op_dcbz_user,
&gen_op_dcbz_user,
&gen_op_dcbz_kernel,
&gen_op_dcbz_kernel,
+ &gen_op_dcbz_64_user,
+ &gen_op_dcbz_64_user,
+ &gen_op_dcbz_64_kernel,
+ &gen_op_dcbz_64_kernel,
};
#endif
+#else
+#if defined(CONFIG_USER_ONLY)
+static GenOpFunc *gen_op_dcbz[] = {
+ &gen_op_dcbz_raw,
+ &gen_op_dcbz_raw,
+};
+#else
+static GenOpFunc *gen_op_dcbz[] = {
+ &gen_op_dcbz_user,
+ &gen_op_dcbz_user,
+ &gen_op_dcbz_kernel,
+ &gen_op_dcbz_kernel,
+};
+#endif
+#endif
GEN_HANDLER(dcbz, 0x1F, 0x16, 0x1F, 0x03E00001, PPC_CACHE)
{
- if (rA(ctx->opcode) == 0) {
- gen_op_load_gpr_T0(rB(ctx->opcode));
- } else {
- gen_op_load_gpr_T0(rA(ctx->opcode));
- gen_op_load_gpr_T1(rB(ctx->opcode));
- gen_op_add();
- }
+ gen_addr_reg_index(ctx);
op_dcbz();
gen_op_check_reservation();
}
/* icbi */
+#define op_icbi() (*gen_op_icbi[ctx->mem_idx])()
+#if defined(TARGET_PPC64)
+#if defined(CONFIG_USER_ONLY)
+static GenOpFunc *gen_op_icbi[] = {
+ &gen_op_icbi_raw,
+ &gen_op_icbi_raw,
+ &gen_op_icbi_64_raw,
+ &gen_op_icbi_64_raw,
+};
+#else
+static GenOpFunc *gen_op_icbi[] = {
+ &gen_op_icbi_user,
+ &gen_op_icbi_user,
+ &gen_op_icbi_kernel,
+ &gen_op_icbi_kernel,
+ &gen_op_icbi_64_user,
+ &gen_op_icbi_64_user,
+ &gen_op_icbi_64_kernel,
+ &gen_op_icbi_64_kernel,
+};
+#endif
+#else
+#if defined(CONFIG_USER_ONLY)
+static GenOpFunc *gen_op_icbi[] = {
+ &gen_op_icbi_raw,
+ &gen_op_icbi_raw,
+};
+#else
+static GenOpFunc *gen_op_icbi[] = {
+ &gen_op_icbi_user,
+ &gen_op_icbi_user,
+ &gen_op_icbi_kernel,
+ &gen_op_icbi_kernel,
+};
+#endif
+#endif
GEN_HANDLER(icbi, 0x1F, 0x16, 0x1E, 0x03E00001, PPC_CACHE)
{
- if (rA(ctx->opcode) == 0) {
- gen_op_load_gpr_T0(rB(ctx->opcode));
- } else {
- gen_op_load_gpr_T0(rA(ctx->opcode));
- gen_op_load_gpr_T1(rB(ctx->opcode));
- gen_op_add();
- }
- gen_op_icbi();
+ /* NIP cannot be restored if the memory exception comes from an helper */
+ gen_update_nip(ctx, ctx->nip - 4);
+ gen_addr_reg_index(ctx);
+ op_icbi();
+ RET_STOP(ctx);
}
/* Optional: */
@@ -2264,11 +3307,12 @@
#if defined(CONFIG_USER_ONLY)
RET_PRIVREG(ctx);
#else
- if (!ctx->supervisor) {
+ if (unlikely(!ctx->supervisor)) {
RET_PRIVREG(ctx);
return;
}
- gen_op_load_sr(SR(ctx->opcode));
+ gen_op_set_T1(SR(ctx->opcode));
+ gen_op_load_sr();
gen_op_store_T0_gpr(rD(ctx->opcode));
#endif
}
@@ -2279,12 +3323,13 @@
#if defined(CONFIG_USER_ONLY)
RET_PRIVREG(ctx);
#else
- if (!ctx->supervisor) {
+ if (unlikely(!ctx->supervisor)) {
RET_PRIVREG(ctx);
return;
}
gen_op_load_gpr_T1(rB(ctx->opcode));
- gen_op_load_srin();
+ gen_op_srli_T1(28);
+ gen_op_load_sr();
gen_op_store_T0_gpr(rD(ctx->opcode));
#endif
}
@@ -2295,12 +3340,13 @@
#if defined(CONFIG_USER_ONLY)
RET_PRIVREG(ctx);
#else
- if (!ctx->supervisor) {
+ if (unlikely(!ctx->supervisor)) {
RET_PRIVREG(ctx);
return;
}
gen_op_load_gpr_T0(rS(ctx->opcode));
- gen_op_store_sr(SR(ctx->opcode));
+ gen_op_set_T1(SR(ctx->opcode));
+ gen_op_store_sr();
RET_STOP(ctx);
#endif
}
@@ -2311,13 +3357,14 @@
#if defined(CONFIG_USER_ONLY)
RET_PRIVREG(ctx);
#else
- if (!ctx->supervisor) {
+ if (unlikely(!ctx->supervisor)) {
RET_PRIVREG(ctx);
return;
}
gen_op_load_gpr_T0(rS(ctx->opcode));
gen_op_load_gpr_T1(rB(ctx->opcode));
- gen_op_store_srin();
+ gen_op_srli_T1(28);
+ gen_op_store_sr();
RET_STOP(ctx);
#endif
}
@@ -2330,8 +3377,8 @@
#if defined(CONFIG_USER_ONLY)
RET_PRIVOPC(ctx);
#else
- if (!ctx->supervisor) {
- if (loglevel)
+ if (unlikely(!ctx->supervisor)) {
+ if (loglevel != 0)
fprintf(logfile, "%s: ! supervisor\n", __func__);
RET_PRIVOPC(ctx);
return;
@@ -2342,28 +3389,33 @@
}
/* tlbie */
-GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x03FF0001, PPC_MEM)
+GEN_HANDLER(tlbie, 0x1F, 0x12, 0x09, 0x03FF0001, PPC_MEM_TLBIE)
{
#if defined(CONFIG_USER_ONLY)
RET_PRIVOPC(ctx);
#else
- if (!ctx->supervisor) {
+ if (unlikely(!ctx->supervisor)) {
RET_PRIVOPC(ctx);
return;
}
gen_op_load_gpr_T0(rB(ctx->opcode));
- gen_op_tlbie();
+#if defined(TARGET_PPC64)
+ if (ctx->sf_mode)
+ gen_op_tlbie_64();
+ else
+#endif
+ gen_op_tlbie();
RET_STOP(ctx);
#endif
}
/* tlbsync */
-GEN_HANDLER(tlbsync, 0x1F, 0x16, 0x11, 0x03FFF801, PPC_MEM)
+GEN_HANDLER(tlbsync, 0x1F, 0x16, 0x11, 0x03FFF801, PPC_MEM_TLBSYNC)
{
#if defined(CONFIG_USER_ONLY)
RET_PRIVOPC(ctx);
#else
- if (!ctx->supervisor) {
+ if (unlikely(!ctx->supervisor)) {
RET_PRIVOPC(ctx);
return;
}
@@ -2374,18 +3426,58 @@
#endif
}
+#if defined(TARGET_PPC64)
+/* slbia */
+GEN_HANDLER(slbia, 0x1F, 0x12, 0x0F, 0x03FFFC01, PPC_SLBI)
+{
+#if defined(CONFIG_USER_ONLY)
+ RET_PRIVOPC(ctx);
+#else
+ if (unlikely(!ctx->supervisor)) {
+ if (loglevel != 0)
+ fprintf(logfile, "%s: ! supervisor\n", __func__);
+ RET_PRIVOPC(ctx);
+ return;
+ }
+ gen_op_slbia();
+ RET_STOP(ctx);
+#endif
+}
+
+/* slbie */
+GEN_HANDLER(slbie, 0x1F, 0x12, 0x0D, 0x03FF0001, PPC_SLBI)
+{
+#if defined(CONFIG_USER_ONLY)
+ RET_PRIVOPC(ctx);
+#else
+ if (unlikely(!ctx->supervisor)) {
+ RET_PRIVOPC(ctx);
+ return;
+ }
+ gen_op_load_gpr_T0(rB(ctx->opcode));
+ gen_op_slbie();
+ RET_STOP(ctx);
+#endif
+}
+#endif
+
/*** External control ***/
/* Optional: */
#define op_eciwx() (*gen_op_eciwx[ctx->mem_idx])()
#define op_ecowx() (*gen_op_ecowx[ctx->mem_idx])()
+#if defined(TARGET_PPC64)
#if defined(CONFIG_USER_ONLY)
static GenOpFunc *gen_op_eciwx[] = {
&gen_op_eciwx_raw,
&gen_op_eciwx_le_raw,
+ &gen_op_eciwx_64_raw,
+ &gen_op_eciwx_le_64_raw,
};
static GenOpFunc *gen_op_ecowx[] = {
&gen_op_ecowx_raw,
&gen_op_ecowx_le_raw,
+ &gen_op_ecowx_64_raw,
+ &gen_op_ecowx_le_64_raw,
};
#else
static GenOpFunc *gen_op_eciwx[] = {
@@ -2393,26 +3485,53 @@
&gen_op_eciwx_le_user,
&gen_op_eciwx_kernel,
&gen_op_eciwx_le_kernel,
+ &gen_op_eciwx_64_user,
+ &gen_op_eciwx_le_64_user,
+ &gen_op_eciwx_64_kernel,
+ &gen_op_eciwx_le_64_kernel,
};
static GenOpFunc *gen_op_ecowx[] = {
&gen_op_ecowx_user,
&gen_op_ecowx_le_user,
&gen_op_ecowx_kernel,
&gen_op_ecowx_le_kernel,
+ &gen_op_ecowx_64_user,
+ &gen_op_ecowx_le_64_user,
+ &gen_op_ecowx_64_kernel,
+ &gen_op_ecowx_le_64_kernel,
};
#endif
+#else
+#if defined(CONFIG_USER_ONLY)
+static GenOpFunc *gen_op_eciwx[] = {
+ &gen_op_eciwx_raw,
+ &gen_op_eciwx_le_raw,
+};
+static GenOpFunc *gen_op_ecowx[] = {
+ &gen_op_ecowx_raw,
+ &gen_op_ecowx_le_raw,
+};
+#else
+static GenOpFunc *gen_op_eciwx[] = {
+ &gen_op_eciwx_user,
+ &gen_op_eciwx_le_user,
+ &gen_op_eciwx_kernel,
+ &gen_op_eciwx_le_kernel,
+};
+static GenOpFunc *gen_op_ecowx[] = {
+ &gen_op_ecowx_user,
+ &gen_op_ecowx_le_user,
+ &gen_op_ecowx_kernel,
+ &gen_op_ecowx_le_kernel,
+};
+#endif
+#endif
/* eciwx */
GEN_HANDLER(eciwx, 0x1F, 0x16, 0x0D, 0x00000001, PPC_EXTERN)
{
/* Should check EAR[E] & alignment ! */
- if (rA(ctx->opcode) == 0) {
- gen_op_load_gpr_T0(rB(ctx->opcode));
- } else {
- gen_op_load_gpr_T0(rA(ctx->opcode));
- gen_op_load_gpr_T1(rB(ctx->opcode));
- gen_op_add();
- }
+ gen_addr_reg_index(ctx);
op_eciwx();
gen_op_store_T0_gpr(rD(ctx->opcode));
}
@@ -2421,17 +3540,2035 @@
GEN_HANDLER(ecowx, 0x1F, 0x16, 0x09, 0x00000001, PPC_EXTERN)
{
/* Should check EAR[E] & alignment ! */
+ gen_addr_reg_index(ctx);
+ gen_op_load_gpr_T1(rS(ctx->opcode));
+ op_ecowx();
+}
+
+/* PowerPC 601 specific instructions */
+/* abs - abs. */
+GEN_HANDLER(abs, 0x1F, 0x08, 0x0B, 0x0000F800, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rA(ctx->opcode));
+ gen_op_POWER_abs();
+ gen_op_store_T0_gpr(rD(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* abso - abso. */
+GEN_HANDLER(abso, 0x1F, 0x08, 0x1B, 0x0000F800, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rA(ctx->opcode));
+ gen_op_POWER_abso();
+ gen_op_store_T0_gpr(rD(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* clcs */
+GEN_HANDLER(clcs, 0x1F, 0x10, 0x13, 0x0000F800, PPC_POWER_BR) /* 601 ? */
+{
+ gen_op_load_gpr_T0(rA(ctx->opcode));
+ gen_op_POWER_clcs();
+ gen_op_store_T0_gpr(rD(ctx->opcode));
+}
+
+/* div - div. */
+GEN_HANDLER(div, 0x1F, 0x0B, 0x0A, 0x00000000, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rA(ctx->opcode));
+ gen_op_load_gpr_T1(rB(ctx->opcode));
+ gen_op_POWER_div();
+ gen_op_store_T0_gpr(rD(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* divo - divo. */
+GEN_HANDLER(divo, 0x1F, 0x0B, 0x1A, 0x00000000, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rA(ctx->opcode));
+ gen_op_load_gpr_T1(rB(ctx->opcode));
+ gen_op_POWER_divo();
+ gen_op_store_T0_gpr(rD(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* divs - divs. */
+GEN_HANDLER(divs, 0x1F, 0x0B, 0x0B, 0x00000000, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rA(ctx->opcode));
+ gen_op_load_gpr_T1(rB(ctx->opcode));
+ gen_op_POWER_divs();
+ gen_op_store_T0_gpr(rD(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* divso - divso. */
+GEN_HANDLER(divso, 0x1F, 0x0B, 0x1B, 0x00000000, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rA(ctx->opcode));
+ gen_op_load_gpr_T1(rB(ctx->opcode));
+ gen_op_POWER_divso();
+ gen_op_store_T0_gpr(rD(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* doz - doz. */
+GEN_HANDLER(doz, 0x1F, 0x08, 0x08, 0x00000000, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rA(ctx->opcode));
+ gen_op_load_gpr_T1(rB(ctx->opcode));
+ gen_op_POWER_doz();
+ gen_op_store_T0_gpr(rD(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* dozo - dozo. */
+GEN_HANDLER(dozo, 0x1F, 0x08, 0x18, 0x00000000, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rA(ctx->opcode));
+ gen_op_load_gpr_T1(rB(ctx->opcode));
+ gen_op_POWER_dozo();
+ gen_op_store_T0_gpr(rD(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* dozi */
+GEN_HANDLER(dozi, 0x09, 0xFF, 0xFF, 0x00000000, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rA(ctx->opcode));
+ gen_op_set_T1(SIMM(ctx->opcode));
+ gen_op_POWER_doz();
+ gen_op_store_T0_gpr(rD(ctx->opcode));
+}
+
+/* As lscbx load from memory byte after byte, it's always endian safe */
+#define op_POWER_lscbx(start, ra, rb) \
+(*gen_op_POWER_lscbx[ctx->mem_idx])(start, ra, rb)
+#if defined(CONFIG_USER_ONLY)
+static GenOpFunc3 *gen_op_POWER_lscbx[] = {
+ &gen_op_POWER_lscbx_raw,
+ &gen_op_POWER_lscbx_raw,
+};
+#else
+static GenOpFunc3 *gen_op_POWER_lscbx[] = {
+ &gen_op_POWER_lscbx_user,
+ &gen_op_POWER_lscbx_user,
+ &gen_op_POWER_lscbx_kernel,
+ &gen_op_POWER_lscbx_kernel,
+};
+#endif
+
+/* lscbx - lscbx. */
+GEN_HANDLER(lscbx, 0x1F, 0x15, 0x08, 0x00000000, PPC_POWER_BR)
+{
+ int ra = rA(ctx->opcode);
+ int rb = rB(ctx->opcode);
+
+ gen_addr_reg_index(ctx);
+ if (ra == 0) {
+ ra = rb;
+ }
+ /* NIP cannot be restored if the memory exception comes from an helper */
+ gen_update_nip(ctx, ctx->nip - 4);
+ gen_op_load_xer_bc();
+ gen_op_load_xer_cmp();
+ op_POWER_lscbx(rD(ctx->opcode), ra, rb);
+ gen_op_store_xer_bc();
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* maskg - maskg. */
+GEN_HANDLER(maskg, 0x1F, 0x1D, 0x00, 0x00000000, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rS(ctx->opcode));
+ gen_op_load_gpr_T1(rB(ctx->opcode));
+ gen_op_POWER_maskg();
+ gen_op_store_T0_gpr(rA(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* maskir - maskir. */
+GEN_HANDLER(maskir, 0x1F, 0x1D, 0x10, 0x00000000, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rA(ctx->opcode));
+ gen_op_load_gpr_T1(rS(ctx->opcode));
+ gen_op_load_gpr_T2(rB(ctx->opcode));
+ gen_op_POWER_maskir();
+ gen_op_store_T0_gpr(rA(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* mul - mul. */
+GEN_HANDLER(mul, 0x1F, 0x0B, 0x03, 0x00000000, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rA(ctx->opcode));
+ gen_op_load_gpr_T1(rB(ctx->opcode));
+ gen_op_POWER_mul();
+ gen_op_store_T0_gpr(rD(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* mulo - mulo. */
+GEN_HANDLER(mulo, 0x1F, 0x0B, 0x13, 0x00000000, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rA(ctx->opcode));
+ gen_op_load_gpr_T1(rB(ctx->opcode));
+ gen_op_POWER_mulo();
+ gen_op_store_T0_gpr(rD(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* nabs - nabs. */
+GEN_HANDLER(nabs, 0x1F, 0x08, 0x0F, 0x00000000, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rA(ctx->opcode));
+ gen_op_POWER_nabs();
+ gen_op_store_T0_gpr(rD(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* nabso - nabso. */
+GEN_HANDLER(nabso, 0x1F, 0x08, 0x1F, 0x00000000, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rA(ctx->opcode));
+ gen_op_POWER_nabso();
+ gen_op_store_T0_gpr(rD(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* rlmi - rlmi. */
+GEN_HANDLER(rlmi, 0x16, 0xFF, 0xFF, 0x00000000, PPC_POWER_BR)
+{
+ uint32_t mb, me;
+
+ mb = MB(ctx->opcode);
+ me = ME(ctx->opcode);
+ gen_op_load_gpr_T0(rS(ctx->opcode));
+ gen_op_load_gpr_T1(rA(ctx->opcode));
+ gen_op_load_gpr_T2(rB(ctx->opcode));
+ gen_op_POWER_rlmi(MASK(mb, me), ~MASK(mb, me));
+ gen_op_store_T0_gpr(rA(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* rrib - rrib. */
+GEN_HANDLER(rrib, 0x1F, 0x19, 0x10, 0x00000000, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rS(ctx->opcode));
+ gen_op_load_gpr_T1(rA(ctx->opcode));
+ gen_op_load_gpr_T2(rB(ctx->opcode));
+ gen_op_POWER_rrib();
+ gen_op_store_T0_gpr(rA(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* sle - sle. */
+GEN_HANDLER(sle, 0x1F, 0x19, 0x04, 0x00000000, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rS(ctx->opcode));
+ gen_op_load_gpr_T1(rB(ctx->opcode));
+ gen_op_POWER_sle();
+ gen_op_store_T0_gpr(rA(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* sleq - sleq. */
+GEN_HANDLER(sleq, 0x1F, 0x19, 0x06, 0x00000000, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rS(ctx->opcode));
+ gen_op_load_gpr_T1(rB(ctx->opcode));
+ gen_op_POWER_sleq();
+ gen_op_store_T0_gpr(rA(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* sliq - sliq. */
+GEN_HANDLER(sliq, 0x1F, 0x18, 0x05, 0x00000000, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rS(ctx->opcode));
+ gen_op_set_T1(SH(ctx->opcode));
+ gen_op_POWER_sle();
+ gen_op_store_T0_gpr(rA(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* slliq - slliq. */
+GEN_HANDLER(slliq, 0x1F, 0x18, 0x07, 0x00000000, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rS(ctx->opcode));
+ gen_op_set_T1(SH(ctx->opcode));
+ gen_op_POWER_sleq();
+ gen_op_store_T0_gpr(rA(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* sllq - sllq. */
+GEN_HANDLER(sllq, 0x1F, 0x18, 0x06, 0x00000000, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rS(ctx->opcode));
+ gen_op_load_gpr_T1(rB(ctx->opcode));
+ gen_op_POWER_sllq();
+ gen_op_store_T0_gpr(rA(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* slq - slq. */
+GEN_HANDLER(slq, 0x1F, 0x18, 0x04, 0x00000000, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rS(ctx->opcode));
+ gen_op_load_gpr_T1(rB(ctx->opcode));
+ gen_op_POWER_slq();
+ gen_op_store_T0_gpr(rA(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* sraiq - sraiq. */
+GEN_HANDLER(sraiq, 0x1F, 0x18, 0x1D, 0x00000000, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rS(ctx->opcode));
+ gen_op_set_T1(SH(ctx->opcode));
+ gen_op_POWER_sraq();
+ gen_op_store_T0_gpr(rA(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* sraq - sraq. */
+GEN_HANDLER(sraq, 0x1F, 0x18, 0x1C, 0x00000000, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rS(ctx->opcode));
+ gen_op_load_gpr_T1(rB(ctx->opcode));
+ gen_op_POWER_sraq();
+ gen_op_store_T0_gpr(rA(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* sre - sre. */
+GEN_HANDLER(sre, 0x1F, 0x19, 0x14, 0x00000000, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rS(ctx->opcode));
+ gen_op_load_gpr_T1(rB(ctx->opcode));
+ gen_op_POWER_sre();
+ gen_op_store_T0_gpr(rA(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* srea - srea. */
+GEN_HANDLER(srea, 0x1F, 0x19, 0x1C, 0x00000000, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rS(ctx->opcode));
+ gen_op_load_gpr_T1(rB(ctx->opcode));
+ gen_op_POWER_srea();
+ gen_op_store_T0_gpr(rA(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* sreq */
+GEN_HANDLER(sreq, 0x1F, 0x19, 0x16, 0x00000000, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rS(ctx->opcode));
+ gen_op_load_gpr_T1(rB(ctx->opcode));
+ gen_op_POWER_sreq();
+ gen_op_store_T0_gpr(rA(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* sriq */
+GEN_HANDLER(sriq, 0x1F, 0x18, 0x15, 0x00000000, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rS(ctx->opcode));
+ gen_op_set_T1(SH(ctx->opcode));
+ gen_op_POWER_srq();
+ gen_op_store_T0_gpr(rA(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* srliq */
+GEN_HANDLER(srliq, 0x1F, 0x18, 0x17, 0x00000000, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rS(ctx->opcode));
+ gen_op_load_gpr_T1(rB(ctx->opcode));
+ gen_op_set_T1(SH(ctx->opcode));
+ gen_op_POWER_srlq();
+ gen_op_store_T0_gpr(rA(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* srlq */
+GEN_HANDLER(srlq, 0x1F, 0x18, 0x16, 0x00000000, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rS(ctx->opcode));
+ gen_op_load_gpr_T1(rB(ctx->opcode));
+ gen_op_POWER_srlq();
+ gen_op_store_T0_gpr(rA(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* srq */
+GEN_HANDLER(srq, 0x1F, 0x18, 0x14, 0x00000000, PPC_POWER_BR)
+{
+ gen_op_load_gpr_T0(rS(ctx->opcode));
+ gen_op_load_gpr_T1(rB(ctx->opcode));
+ gen_op_POWER_srq();
+ gen_op_store_T0_gpr(rA(ctx->opcode));
+ if (unlikely(Rc(ctx->opcode) != 0))
+ gen_set_Rc0(ctx);
+}
+
+/* PowerPC 602 specific instructions */
+/* dsa */
+GEN_HANDLER(dsa, 0x1F, 0x14, 0x13, 0x03FFF801, PPC_602_SPEC)
+{
+ /* XXX: TODO */
+ RET_INVAL(ctx);
+}
+
+/* esa */
+GEN_HANDLER(esa, 0x1F, 0x14, 0x12, 0x03FFF801, PPC_602_SPEC)
+{
+ /* XXX: TODO */
+ RET_INVAL(ctx);
+}
+
+/* mfrom */
+GEN_HANDLER(mfrom, 0x1F, 0x09, 0x08, 0x03E0F801, PPC_602_SPEC)
+{
+#if defined(CONFIG_USER_ONLY)
+ RET_PRIVOPC(ctx);
+#else
+ if (unlikely(!ctx->supervisor)) {
+ RET_PRIVOPC(ctx);
+ return;
+ }
+ gen_op_load_gpr_T0(rA(ctx->opcode));
+ gen_op_602_mfrom();
+ gen_op_store_T0_gpr(rD(ctx->opcode));
+#endif
+}
+
+/* 602 - 603 - G2 TLB management */
+/* tlbld */
+GEN_HANDLER(tlbld, 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_6xx_TLB)
+{
+#if defined(CONFIG_USER_ONLY)
+ RET_PRIVOPC(ctx);
+#else
+ if (unlikely(!ctx->supervisor)) {
+ RET_PRIVOPC(ctx);
+ return;
+ }
+ gen_op_load_gpr_T0(rB(ctx->opcode));
+ gen_op_6xx_tlbld();
+ RET_STOP(ctx);
+#endif
+}
+
+/* tlbli */
+GEN_HANDLER(tlbli, 0x1F, 0x12, 0x1F, 0x03FF0001, PPC_6xx_TLB)
+{
+#if defined(CONFIG_USER_ONLY)
+ RET_PRIVOPC(ctx);
+#else
+ if (unlikely(!ctx->supervisor)) {
+ RET_PRIVOPC(ctx);
+ return;
+ }
+ gen_op_load_gpr_T0(rB(ctx->opcode));
+ gen_op_6xx_tlbli();
+ RET_STOP(ctx);
+#endif
+}
+
+/* POWER instructions not in PowerPC 601 */
+/* clf */
+GEN_HANDLER(clf, 0x1F, 0x16, 0x03, 0x03E00000, PPC_POWER)
+{
+ /* Cache line flush: implemented as no-op */
+}
+
+/* cli */
+GEN_HANDLER(cli, 0x1F, 0x16, 0x0F, 0x03E00000, PPC_POWER)
+{
+ /* Cache line invalidate: priviledged and treated as no-op */
+#if defined(CONFIG_USER_ONLY)
+ RET_PRIVOPC(ctx);
+#else
+ if (unlikely(!ctx->supervisor)) {
+ RET_PRIVOPC(ctx);
+ return;
+ }
+#endif
+}
+
+/* dclst */
+GEN_HANDLER(dclst, 0x1F, 0x16, 0x13, 0x03E00000, PPC_POWER)
+{
+ /* Data cache line store: treated as no-op */
+}
+
+GEN_HANDLER(mfsri, 0x1F, 0x13, 0x13, 0x00000001, PPC_POWER)
+{
+#if defined(CONFIG_USER_ONLY)
+ RET_PRIVOPC(ctx);
+#else
+ if (unlikely(!ctx->supervisor)) {
+ RET_PRIVOPC(ctx);
+ return;
+ }
+ int ra = rA(ctx->opcode);
+ int rd = rD(ctx->opcode);
+
+ gen_addr_reg_index(ctx);
+ gen_op_POWER_mfsri();
+ gen_op_store_T0_gpr(rd);
+ if (ra != 0 && ra != rd)
+ gen_op_store_T1_gpr(ra);
+#endif
+}
+
+GEN_HANDLER(rac, 0x1F, 0x12, 0x19, 0x00000001, PPC_POWER)
+{
+#if defined(CONFIG_USER_ONLY)
+ RET_PRIVOPC(ctx);
+#else
+ if (unlikely(!ctx->supervisor)) {
+ RET_PRIVOPC(ctx);
+ return;
+ }
+ gen_addr_reg_index(ctx);
+ gen_op_POWER_rac();
+ gen_op_store_T0_gpr(rD(ctx->opcode));
+#endif
+}
+
+GEN_HANDLER(rfsvc, 0x13, 0x12, 0x02, 0x03FFF0001, PPC_POWER)
+{
+#if defined(CONFIG_USER_ONLY)
+ RET_PRIVOPC(ctx);
+#else
+ if (unlikely(!ctx->supervisor)) {
+ RET_PRIVOPC(ctx);
+ return;
+ }
+ gen_op_POWER_rfsvc();
+ RET_CHG_FLOW(ctx);
+#endif
+}
+
+/* svc is not implemented for now */
+
+/* POWER2 specific instructions */
+/* Quad manipulation (load/store two floats at a time) */
+#define op_POWER2_lfq() (*gen_op_POWER2_lfq[ctx->mem_idx])()
+#define op_POWER2_stfq() (*gen_op_POWER2_stfq[ctx->mem_idx])()
+#if defined(CONFIG_USER_ONLY)
+static GenOpFunc *gen_op_POWER2_lfq[] = {
+ &gen_op_POWER2_lfq_le_raw,
+ &gen_op_POWER2_lfq_raw,
+};
+static GenOpFunc *gen_op_POWER2_stfq[] = {
+ &gen_op_POWER2_stfq_le_raw,
+ &gen_op_POWER2_stfq_raw,
+};
+#else
+static GenOpFunc *gen_op_POWER2_lfq[] = {
+ &gen_op_POWER2_lfq_le_user,
+ &gen_op_POWER2_lfq_user,
+ &gen_op_POWER2_lfq_le_kernel,
+ &gen_op_POWER2_lfq_kernel,
+};
+static GenOpFunc *gen_op_POWER2_stfq[] = {
+ &gen_op_POWER2_stfq_le_user,
+ &gen_op_POWER2_stfq_user,
+ &gen_op_POWER2_stfq_le_kernel,
+ &gen_op_POWER2_stfq_kernel,
+};
+#endif
+
+/* lfq */
+GEN_HANDLER(lfq, 0x38, 0xFF, 0xFF, 0x00000003, PPC_POWER2)
+{
+ /* NIP cannot be restored if the memory exception comes from an helper */
+ gen_update_nip(ctx, ctx->nip - 4);
+ gen_addr_imm_index(ctx, 0);
+ op_POWER2_lfq();
+ gen_op_store_FT0_fpr(rD(ctx->opcode));
+ gen_op_store_FT1_fpr(rD(ctx->opcode) + 1);
+}
+
+/* lfqu */
+GEN_HANDLER(lfqu, 0x39, 0xFF, 0xFF, 0x00000003, PPC_POWER2)
+{
+ int ra = rA(ctx->opcode);
+
+ /* NIP cannot be restored if the memory exception comes from an helper */
+ gen_update_nip(ctx, ctx->nip - 4);
+ gen_addr_imm_index(ctx, 0);
+ op_POWER2_lfq();
+ gen_op_store_FT0_fpr(rD(ctx->opcode));
+ gen_op_store_FT1_fpr(rD(ctx->opcode) + 1);
+ if (ra != 0)
+ gen_op_store_T0_gpr(ra);
+}
+
+/* lfqux */
+GEN_HANDLER(lfqux, 0x1F, 0x17, 0x19, 0x00000001, PPC_POWER2)
+{
+ int ra = rA(ctx->opcode);
+
+ /* NIP cannot be restored if the memory exception comes from an helper */
+ gen_update_nip(ctx, ctx->nip - 4);
+ gen_addr_reg_index(ctx);
+ op_POWER2_lfq();
+ gen_op_store_FT0_fpr(rD(ctx->opcode));
+ gen_op_store_FT1_fpr(rD(ctx->opcode) + 1);
+ if (ra != 0)
+ gen_op_store_T0_gpr(ra);
+}
+
+/* lfqx */
+GEN_HANDLER(lfqx, 0x1F, 0x17, 0x18, 0x00000001, PPC_POWER2)
+{
+ /* NIP cannot be restored if the memory exception comes from an helper */
+ gen_update_nip(ctx, ctx->nip - 4);
+ gen_addr_reg_index(ctx);
+ op_POWER2_lfq();
+ gen_op_store_FT0_fpr(rD(ctx->opcode));
+ gen_op_store_FT1_fpr(rD(ctx->opcode) + 1);
+}
+
+/* stfq */
+GEN_HANDLER(stfq, 0x3C, 0xFF, 0xFF, 0x00000003, PPC_POWER2)
+{
+ /* NIP cannot be restored if the memory exception comes from an helper */
+ gen_update_nip(ctx, ctx->nip - 4);
+ gen_addr_imm_index(ctx, 0);
+ gen_op_load_fpr_FT0(rS(ctx->opcode));
+ gen_op_load_fpr_FT1(rS(ctx->opcode) + 1);
+ op_POWER2_stfq();
+}
+
+/* stfqu */
+GEN_HANDLER(stfqu, 0x3D, 0xFF, 0xFF, 0x00000003, PPC_POWER2)
+{
+ int ra = rA(ctx->opcode);
+
+ /* NIP cannot be restored if the memory exception comes from an helper */
+ gen_update_nip(ctx, ctx->nip - 4);
+ gen_addr_imm_index(ctx, 0);
+ gen_op_load_fpr_FT0(rS(ctx->opcode));
+ gen_op_load_fpr_FT1(rS(ctx->opcode) + 1);
+ op_POWER2_stfq();
+ if (ra != 0)
+ gen_op_store_T0_gpr(ra);
+}
+
+/* stfqux */
+GEN_HANDLER(stfqux, 0x1F, 0x17, 0x1D, 0x00000001, PPC_POWER2)
+{
+ int ra = rA(ctx->opcode);
+
+ /* NIP cannot be restored if the memory exception comes from an helper */
+ gen_update_nip(ctx, ctx->nip - 4);
+ gen_addr_reg_index(ctx);
+ gen_op_load_fpr_FT0(rS(ctx->opcode));
+ gen_op_load_fpr_FT1(rS(ctx->opcode) + 1);
+ op_POWER2_stfq();
+ if (ra != 0)
+ gen_op_store_T0_gpr(ra);
+}
+
+/* stfqx */
+GEN_HANDLER(stfqx, 0x1F, 0x17, 0x1C, 0x00000001, PPC_POWER2)
+{
+ /* NIP cannot be restored if the memory exception comes from an helper */
+ gen_update_nip(ctx, ctx->nip - 4);
+ gen_addr_reg_index(ctx);
+ gen_op_load_fpr_FT0(rS(ctx->opcode));
+ gen_op_load_fpr_FT1(rS(ctx->opcode) + 1);
+ op_POWER2_stfq();
+}
+
+/* BookE specific instructions */
+GEN_HANDLER(mfapidi, 0x1F, 0x13, 0x08, 0x0000F801, PPC_BOOKE)
+{
+ /* XXX: TODO */
+ RET_INVAL(ctx);
+}
+
+GEN_HANDLER(tlbiva, 0x1F, 0x12, 0x18, 0x03FFF801, PPC_BOOKE)
+{
+#if defined(CONFIG_USER_ONLY)
+ RET_PRIVOPC(ctx);
+#else
+ if (unlikely(!ctx->supervisor)) {
+ RET_PRIVOPC(ctx);
+ return;
+ }
+ gen_addr_reg_index(ctx);
+ /* Use the same micro-ops as for tlbie */
+#if defined(TARGET_PPC64)
+ if (ctx->sf_mode)
+ gen_op_tlbie_64();
+ else
+#endif
+ gen_op_tlbie();
+ RET_STOP(ctx);
+#endif
+}
+
+/* All 405 MAC instructions are translated here */
+static inline void gen_405_mulladd_insn (DisasContext *ctx, int opc2, int opc3,
+ int ra, int rb, int rt, int Rc)
+{
+ gen_op_load_gpr_T0(ra);
+ gen_op_load_gpr_T1(rb);
+ switch (opc3 & 0x0D) {
+ case 0x05:
+ /* macchw - macchw. - macchwo - macchwo. */
+ /* macchws - macchws. - macchwso - macchwso. */
+ /* nmacchw - nmacchw. - nmacchwo - nmacchwo. */
+ /* nmacchws - nmacchws. - nmacchwso - nmacchwso. */
+ /* mulchw - mulchw. */
+ gen_op_405_mulchw();
+ break;
+ case 0x04:
+ /* macchwu - macchwu. - macchwuo - macchwuo. */
+ /* macchwsu - macchwsu. - macchwsuo - macchwsuo. */
+ /* mulchwu - mulchwu. */
+ gen_op_405_mulchwu();
+ break;
+ case 0x01:
+ /* machhw - machhw. - machhwo - machhwo. */
+ /* machhws - machhws. - machhwso - machhwso. */
+ /* nmachhw - nmachhw. - nmachhwo - nmachhwo. */
+ /* nmachhws - nmachhws. - nmachhwso - nmachhwso. */
+ /* mulhhw - mulhhw. */
+ gen_op_405_mulhhw();
+ break;
+ case 0x00:
+ /* machhwu - machhwu. - machhwuo - machhwuo. */
+ /* machhwsu - machhwsu. - machhwsuo - machhwsuo. */
+ /* mulhhwu - mulhhwu. */
+ gen_op_405_mulhhwu();
+ break;
+ case 0x0D:
+ /* maclhw - maclhw. - maclhwo - maclhwo. */
+ /* maclhws - maclhws. - maclhwso - maclhwso. */
+ /* nmaclhw - nmaclhw. - nmaclhwo - nmaclhwo. */
+ /* nmaclhws - nmaclhws. - nmaclhwso - nmaclhwso. */
+ /* mullhw - mullhw. */
+ gen_op_405_mullhw();
+ break;
+ case 0x0C:
+ /* maclhwu - maclhwu. - maclhwuo - maclhwuo. */
+ /* maclhwsu - maclhwsu. - maclhwsuo - maclhwsuo. */
+ /* mullhwu - mullhwu. */
+ gen_op_405_mullhwu();
+ break;
+ }
+ if (opc2 & 0x02) {
+ /* nmultiply-and-accumulate (0x0E) */
+ gen_op_neg();
+ }
+ if (opc2 & 0x04) {
+ /* (n)multiply-and-accumulate (0x0C - 0x0E) */
+ gen_op_load_gpr_T2(rt);
+ gen_op_move_T1_T0();
+ gen_op_405_add_T0_T2();
+ }
+ if (opc3 & 0x10) {
+ /* Check overflow */
+ if (opc3 & 0x01)
+ gen_op_405_check_ov();
+ else
+ gen_op_405_check_ovu();
+ }
+ if (opc3 & 0x02) {
+ /* Saturate */
+ if (opc3 & 0x01)
+ gen_op_405_check_sat();
+ else
+ gen_op_405_check_satu();
+ }
+ gen_op_store_T0_gpr(rt);
+ if (unlikely(Rc) != 0) {
+ /* Update Rc0 */
+ gen_set_Rc0(ctx);
+ }
+}
+
+#define GEN_MAC_HANDLER(name, opc2, opc3) \
+GEN_HANDLER(name, 0x04, opc2, opc3, 0x00000000, PPC_405_MAC) \
+{ \
+ gen_405_mulladd_insn(ctx, opc2, opc3, rA(ctx->opcode), rB(ctx->opcode), \
+ rD(ctx->opcode), Rc(ctx->opcode)); \
+}
+
+/* macchw - macchw. */
+GEN_MAC_HANDLER(macchw, 0x0C, 0x05);
+/* macchwo - macchwo. */
+GEN_MAC_HANDLER(macchwo, 0x0C, 0x15);
+/* macchws - macchws. */
+GEN_MAC_HANDLER(macchws, 0x0C, 0x07);
+/* macchwso - macchwso. */
+GEN_MAC_HANDLER(macchwso, 0x0C, 0x17);
+/* macchwsu - macchwsu. */
+GEN_MAC_HANDLER(macchwsu, 0x0C, 0x06);
+/* macchwsuo - macchwsuo. */
+GEN_MAC_HANDLER(macchwsuo, 0x0C, 0x16);
+/* macchwu - macchwu. */
+GEN_MAC_HANDLER(macchwu, 0x0C, 0x04);
+/* macchwuo - macchwuo. */
+GEN_MAC_HANDLER(macchwuo, 0x0C, 0x14);
+/* machhw - machhw. */
+GEN_MAC_HANDLER(machhw, 0x0C, 0x01);
+/* machhwo - machhwo. */
+GEN_MAC_HANDLER(machhwo, 0x0C, 0x11);
+/* machhws - machhws. */
+GEN_MAC_HANDLER(machhws, 0x0C, 0x03);
+/* machhwso - machhwso. */
+GEN_MAC_HANDLER(machhwso, 0x0C, 0x13);
+/* machhwsu - machhwsu. */
+GEN_MAC_HANDLER(machhwsu, 0x0C, 0x02);
+/* machhwsuo - machhwsuo. */
+GEN_MAC_HANDLER(machhwsuo, 0x0C, 0x12);
+/* machhwu - machhwu. */
+GEN_MAC_HANDLER(machhwu, 0x0C, 0x00);
+/* machhwuo - machhwuo. */
+GEN_MAC_HANDLER(machhwuo, 0x0C, 0x10);
+/* maclhw - maclhw. */
+GEN_MAC_HANDLER(maclhw, 0x0C, 0x0D);
+/* maclhwo - maclhwo. */
+GEN_MAC_HANDLER(maclhwo, 0x0C, 0x1D);
+/* maclhws - maclhws. */
+GEN_MAC_HANDLER(maclhws, 0x0C, 0x0F);
+/* maclhwso - maclhwso. */
+GEN_MAC_HANDLER(maclhwso, 0x0C, 0x1F);
+/* maclhwu - maclhwu. */
+GEN_MAC_HANDLER(maclhwu, 0x0C, 0x0C);
+/* maclhwuo - maclhwuo. */
+GEN_MAC_HANDLER(maclhwuo, 0x0C, 0x1C);
+/* maclhwsu - maclhwsu. */
+GEN_MAC_HANDLER(maclhwsu, 0x0C, 0x0E);
+/* maclhwsuo - maclhwsuo. */
+GEN_MAC_HANDLER(maclhwsuo, 0x0C, 0x1E);
+/* nmacchw - nmacchw. */
+GEN_MAC_HANDLER(nmacchw, 0x0E, 0x05);
+/* nmacchwo - nmacchwo. */
+GEN_MAC_HANDLER(nmacchwo, 0x0E, 0x15);
+/* nmacchws - nmacchws. */
+GEN_MAC_HANDLER(nmacchws, 0x0E, 0x07);
+/* nmacchwso - nmacchwso. */
+GEN_MAC_HANDLER(nmacchwso, 0x0E, 0x17);
+/* nmachhw - nmachhw. */
+GEN_MAC_HANDLER(nmachhw, 0x0E, 0x01);
+/* nmachhwo - nmachhwo. */
+GEN_MAC_HANDLER(nmachhwo, 0x0E, 0x11);
+/* nmachhws - nmachhws. */
+GEN_MAC_HANDLER(nmachhws, 0x0E, 0x03);
+/* nmachhwso - nmachhwso. */
+GEN_MAC_HANDLER(nmachhwso, 0x0E, 0x13);
+/* nmaclhw - nmaclhw. */
+GEN_MAC_HANDLER(nmaclhw, 0x0E, 0x0D);
+/* nmaclhwo - nmaclhwo. */
+GEN_MAC_HANDLER(nmaclhwo, 0x0E, 0x1D);
+/* nmaclhws - nmaclhws. */
+GEN_MAC_HANDLER(nmaclhws, 0x0E, 0x0F);
+/* nmaclhwso - nmaclhwso. */
+GEN_MAC_HANDLER(nmaclhwso, 0x0E, 0x1F);
+
+/* mulchw - mulchw. */
+GEN_MAC_HANDLER(mulchw, 0x08, 0x05);
+/* mulchwu - mulchwu. */
+GEN_MAC_HANDLER(mulchwu, 0x08, 0x04);
+/* mulhhw - mulhhw. */
+GEN_MAC_HANDLER(mulhhw, 0x08, 0x01);
+/* mulhhwu - mulhhwu. */
+GEN_MAC_HANDLER(mulhhwu, 0x08, 0x00);
+/* mullhw - mullhw. */
+GEN_MAC_HANDLER(mullhw, 0x08, 0x0D);
+/* mullhwu - mullhwu. */
+GEN_MAC_HANDLER(mullhwu, 0x08, 0x0C);
+
+/* mfdcr */
+GEN_HANDLER(mfdcr, 0x1F, 0x03, 0x0A, 0x00000001, PPC_EMB_COMMON)
+{
+#if defined(CONFIG_USER_ONLY)
+ RET_PRIVREG(ctx);
+#else
+ uint32_t dcrn = SPR(ctx->opcode);
+
+ if (unlikely(!ctx->supervisor)) {
+ RET_PRIVREG(ctx);
+ return;
+ }
+ gen_op_set_T0(dcrn);
+ gen_op_load_dcr();
+ gen_op_store_T0_gpr(rD(ctx->opcode));
+#endif
+}
+
+/* mtdcr */
+GEN_HANDLER(mtdcr, 0x1F, 0x03, 0x0E, 0x00000001, PPC_EMB_COMMON)
+{
+#if defined(CONFIG_USER_ONLY)
+ RET_PRIVREG(ctx);
+#else
+ uint32_t dcrn = SPR(ctx->opcode);
+
+ if (unlikely(!ctx->supervisor)) {
+ RET_PRIVREG(ctx);
+ return;
+ }
+ gen_op_set_T0(dcrn);
+ gen_op_load_gpr_T1(rS(ctx->opcode));
+ gen_op_store_dcr();
+#endif
+}
+
+/* mfdcrx */
+GEN_HANDLER(mfdcrx, 0x1F, 0x03, 0x08, 0x00000001, PPC_BOOKE)
+{
+#if defined(CONFIG_USER_ONLY)
+ RET_PRIVREG(ctx);
+#else
+ if (unlikely(!ctx->supervisor)) {
+ RET_PRIVREG(ctx);
+ return;
+ }
+ gen_op_load_gpr_T0(rA(ctx->opcode));
+ gen_op_load_dcr();
+ gen_op_store_T0_gpr(rD(ctx->opcode));
+#endif
+}
+
+/* mtdcrx */
+GEN_HANDLER(mtdcrx, 0x1F, 0x03, 0x0C, 0x00000001, PPC_BOOKE)
+{
+#if defined(CONFIG_USER_ONLY)
+ RET_PRIVREG(ctx);
+#else
+ if (unlikely(!ctx->supervisor)) {
+ RET_PRIVREG(ctx);
+ return;
+ }
+ gen_op_load_gpr_T0(rA(ctx->opcode));
+ gen_op_load_gpr_T1(rS(ctx->opcode));
+ gen_op_store_dcr();
+#endif
+}
+
+/* dccci */
+GEN_HANDLER(dccci, 0x1F, 0x06, 0x0E, 0x03E00001, PPC_4xx_COMMON)
+{
+#if defined(CONFIG_USER_ONLY)
+ RET_PRIVOPC(ctx);
+#else
+ if (unlikely(!ctx->supervisor)) {
+ RET_PRIVOPC(ctx);
+ return;
+ }
+ /* interpreted as no-op */
+#endif
+}
+
+/* dcread */
+GEN_HANDLER(dcread, 0x1F, 0x06, 0x0F, 0x00000001, PPC_4xx_COMMON)
+{
+#if defined(CONFIG_USER_ONLY)
+ RET_PRIVOPC(ctx);
+#else
+ if (unlikely(!ctx->supervisor)) {
+ RET_PRIVOPC(ctx);
+ return;
+ }
+ gen_addr_reg_index(ctx);
+ op_ldst(lwz);
+ gen_op_store_T0_gpr(rD(ctx->opcode));
+#endif
+}
+
+/* icbt */
+GEN_HANDLER(icbt_40x, 0x1F, 0x06, 0x08, 0x03E00001, PPC_40x_SPEC)
+{
+ /* interpreted as no-op */
+ /* XXX: specification say this is treated as a load by the MMU
+ * but does not generate any exception
+ */
+}
+
+/* iccci */
+GEN_HANDLER(iccci, 0x1F, 0x06, 0x1E, 0x00000001, PPC_4xx_COMMON)
+{
+#if defined(CONFIG_USER_ONLY)
+ RET_PRIVOPC(ctx);
+#else
+ if (unlikely(!ctx->supervisor)) {
+ RET_PRIVOPC(ctx);
+ return;
+ }
+ /* interpreted as no-op */
+#endif
+}
+
+/* icread */
+GEN_HANDLER(icread, 0x1F, 0x06, 0x1F, 0x03E00001, PPC_4xx_COMMON)
+{
+#if defined(CONFIG_USER_ONLY)
+ RET_PRIVOPC(ctx);
+#else
+ if (unlikely(!ctx->supervisor)) {
+ RET_PRIVOPC(ctx);
+ return;
+ }
+ /* interpreted as no-op */
+#endif
+}
+
+/* rfci (supervisor only) */
+GEN_HANDLER(rfci_40x, 0x13, 0x13, 0x01, 0x03FF8001, PPC_40x_EXCP)
+{
+#if defined(CONFIG_USER_ONLY)
+ RET_PRIVOPC(ctx);
+#else
+ if (unlikely(!ctx->supervisor)) {
+ RET_PRIVOPC(ctx);
+ return;
+ }
+ /* Restore CPU state */
+ gen_op_40x_rfci();
+ RET_CHG_FLOW(ctx);
+#endif
+}
+
+GEN_HANDLER(rfci, 0x13, 0x13, 0x01, 0x03FF8001, PPC_BOOKE)
+{
+#if defined(CONFIG_USER_ONLY)
+ RET_PRIVOPC(ctx);
+#else
+ if (unlikely(!ctx->supervisor)) {
+ RET_PRIVOPC(ctx);
+ return;
+ }
+ /* Restore CPU state */
+ gen_op_rfci();
+ RET_CHG_FLOW(ctx);
+#endif
+}
+
+/* BookE specific */
+GEN_HANDLER(rfdi, 0x13, 0x07, 0x01, 0x03FF8001, PPC_BOOKE)
+{
+#if defined(CONFIG_USER_ONLY)
+ RET_PRIVOPC(ctx);
+#else
+ if (unlikely(!ctx->supervisor)) {
+ RET_PRIVOPC(ctx);
+ return;
+ }
+ /* Restore CPU state */
+ gen_op_rfdi();
+ RET_CHG_FLOW(ctx);
+#endif
+}
+
+GEN_HANDLER(rfmci, 0x13, 0x06, 0x01, 0x03FF8001, PPC_BOOKE)
+{
+#if defined(CONFIG_USER_ONLY)
+ RET_PRIVOPC(ctx);
+#else
+ if (unlikely(!ctx->supervisor)) {
+ RET_PRIVOPC(ctx);
+ return;
+ }
+ /* Restore CPU state */
+ gen_op_rfmci();
+ RET_CHG_FLOW(ctx);
+#endif
+}
+/* TLB management - PowerPC 405 implementation */
+/* tlbre */
+GEN_HANDLER(tlbre, 0x1F, 0x12, 0x1D, 0x00000001, PPC_40x_SPEC)
+{
+#if defined(CONFIG_USER_ONLY)
+ RET_PRIVOPC(ctx);
+#else
+ if (unlikely(!ctx->supervisor)) {
+ RET_PRIVOPC(ctx);
+ return;
+ }
+ switch (rB(ctx->opcode)) {
+ case 0:
+ gen_op_load_gpr_T0(rA(ctx->opcode));
+ gen_op_4xx_tlbre_hi();
+ gen_op_store_T0_gpr(rD(ctx->opcode));
+ break;
+ case 1:
+ gen_op_load_gpr_T0(rA(ctx->opcode));
+ gen_op_4xx_tlbre_lo();
+ gen_op_store_T0_gpr(rD(ctx->opcode));
+ break;
+ default:
+ RET_INVAL(ctx);
+ break;
+ }
+#endif
+}
+
+/* tlbsx - tlbsx. */
+GEN_HANDLER(tlbsx, 0x1F, 0x12, 0x1C, 0x00000000, PPC_40x_SPEC)
+{
+#if defined(CONFIG_USER_ONLY)
+ RET_PRIVOPC(ctx);
+#else
+ if (unlikely(!ctx->supervisor)) {
+ RET_PRIVOPC(ctx);
+ return;
+ }
+ gen_addr_reg_index(ctx);
+ if (Rc(ctx->opcode))
+ gen_op_4xx_tlbsx_();
+ else
+ gen_op_4xx_tlbsx();
+ gen_op_store_T0_gpr(rD(ctx->opcode));
+#endif
+}
+
+/* tlbwe */
+GEN_HANDLER(tlbwe, 0x1F, 0x12, 0x1E, 0x00000001, PPC_40x_SPEC)
+{
+#if defined(CONFIG_USER_ONLY)
+ RET_PRIVOPC(ctx);
+#else
+ if (unlikely(!ctx->supervisor)) {
+ RET_PRIVOPC(ctx);
+ return;
+ }
+ switch (rB(ctx->opcode)) {
+ case 0:
+ gen_op_load_gpr_T0(rA(ctx->opcode));
+ gen_op_load_gpr_T1(rS(ctx->opcode));
+ gen_op_4xx_tlbwe_hi();
+ break;
+ case 1:
+ gen_op_load_gpr_T0(rA(ctx->opcode));
+ gen_op_load_gpr_T1(rS(ctx->opcode));
+ gen_op_4xx_tlbwe_lo();
+ break;
+ default:
+ RET_INVAL(ctx);
+ break;
+ }
+#endif
+}
+
+/* wrtee */
+GEN_HANDLER(wrtee, 0x1F, 0x03, 0x04, 0x000FFC01, PPC_EMB_COMMON)
+{
+#if defined(CONFIG_USER_ONLY)
+ RET_PRIVOPC(ctx);
+#else
+ if (unlikely(!ctx->supervisor)) {
+ RET_PRIVOPC(ctx);
+ return;
+ }
+ gen_op_load_gpr_T0(rD(ctx->opcode));
+ gen_op_wrte();
+ RET_EXCP(ctx, EXCP_MTMSR, 0);
+#endif
+}
+
+/* wrteei */
+GEN_HANDLER(wrteei, 0x1F, 0x03, 0x05, 0x000EFC01, PPC_EMB_COMMON)
+{
+#if defined(CONFIG_USER_ONLY)
+ RET_PRIVOPC(ctx);
+#else
+ if (unlikely(!ctx->supervisor)) {
+ RET_PRIVOPC(ctx);
+ return;
+ }
+ gen_op_set_T0(ctx->opcode & 0x00010000);
+ gen_op_wrte();
+ RET_EXCP(ctx, EXCP_MTMSR, 0);
+#endif
+}
+
+/* PowerPC 440 specific instructions */
+/* dlmzb */
+GEN_HANDLER(dlmzb, 0x1F, 0x0E, 0x02, 0x00000000, PPC_440_SPEC)
+{
+ gen_op_load_gpr_T0(rS(ctx->opcode));
+ gen_op_load_gpr_T1(rB(ctx->opcode));
+ gen_op_440_dlmzb();
+ gen_op_store_T0_gpr(rA(ctx->opcode));
+ gen_op_store_xer_bc();
+ if (Rc(ctx->opcode)) {
+ gen_op_440_dlmzb_update_Rc();
+ gen_op_store_T0_crf(0);
+ }
+}
+
+/* mbar replaces eieio on 440 */
+GEN_HANDLER(mbar, 0x1F, 0x16, 0x13, 0x001FF801, PPC_BOOKE)
+{
+ /* interpreted as no-op */
+}
+
+/* msync replaces sync on 440 */
+GEN_HANDLER(msync, 0x1F, 0x16, 0x12, 0x03FF0801, PPC_BOOKE)
+{
+ /* interpreted as no-op */
+}
+
+/* icbt */
+GEN_HANDLER(icbt_440, 0x1F, 0x16, 0x00, 0x03E00001, PPC_BOOKE)
+{
+ /* interpreted as no-op */
+ /* XXX: specification say this is treated as a load by the MMU
+ * but does not generate any exception
+ */
+}
+
+#if defined(TARGET_PPCEMB)
+/*** SPE extension ***/
+
+/* Register moves */
+GEN32(gen_op_load_gpr64_T0, gen_op_load_gpr64_T0_gpr);
+GEN32(gen_op_load_gpr64_T1, gen_op_load_gpr64_T1_gpr);
+#if 0 // unused
+GEN32(gen_op_load_gpr64_T2, gen_op_load_gpr64_T2_gpr);
+#endif
+
+GEN32(gen_op_store_T0_gpr64, gen_op_store_T0_gpr64_gpr);
+GEN32(gen_op_store_T1_gpr64, gen_op_store_T1_gpr64_gpr);
+#if 0 // unused
+GEN32(gen_op_store_T2_gpr64, gen_op_store_T2_gpr64_gpr);
+#endif
+
+#define GEN_SPE(name0, name1, opc2, opc3, inval, type) \
+GEN_HANDLER(name0##_##name1, 0x04, opc2, opc3, inval, type) \
+{ \
+ if (Rc(ctx->opcode)) \
+ gen_##name1(ctx); \
+ else \
+ gen_##name0(ctx); \
+}
+
+/* Handler for undefined SPE opcodes */
+static inline void gen_speundef (DisasContext *ctx)
+{
+ RET_INVAL(ctx);
+}
+
+/* SPE load and stores */
+static inline void gen_addr_spe_imm_index (DisasContext *ctx, int sh)
+{
+ target_long simm = rB(ctx->opcode);
+
if (rA(ctx->opcode) == 0) {
- gen_op_load_gpr_T0(rB(ctx->opcode));
+ gen_set_T0(simm << sh);
} else {
gen_op_load_gpr_T0(rA(ctx->opcode));
- gen_op_load_gpr_T1(rB(ctx->opcode));
- gen_op_add();
+ if (likely(simm != 0))
+ gen_op_addi(simm << sh);
}
- gen_op_load_gpr_T2(rS(ctx->opcode));
- op_ecowx();
}
+#define op_spe_ldst(name) (*gen_op_##name[ctx->mem_idx])()
+#if defined(CONFIG_USER_ONLY)
+#if defined(TARGET_PPC64)
+#define OP_SPE_LD_TABLE(name) \
+static GenOpFunc *gen_op_spe_l##name[] = { \
+ &gen_op_spe_l##name##_raw, \
+ &gen_op_spe_l##name##_le_raw, \
+ &gen_op_spe_l##name##_64_raw, \
+ &gen_op_spe_l##name##_le_64_raw, \
+};
+#define OP_SPE_ST_TABLE(name) \
+static GenOpFunc *gen_op_spe_st##name[] = { \
+ &gen_op_spe_st##name##_raw, \
+ &gen_op_spe_st##name##_le_raw, \
+ &gen_op_spe_st##name##_64_raw, \
+ &gen_op_spe_st##name##_le_64_raw, \
+};
+#else /* defined(TARGET_PPC64) */
+#define OP_SPE_LD_TABLE(name) \
+static GenOpFunc *gen_op_spe_l##name[] = { \
+ &gen_op_spe_l##name##_raw, \
+ &gen_op_spe_l##name##_le_raw, \
+};
+#define OP_SPE_ST_TABLE(name) \
+static GenOpFunc *gen_op_spe_st##name[] = { \
+ &gen_op_spe_st##name##_raw, \
+ &gen_op_spe_st##name##_le_raw, \
+};
+#endif /* defined(TARGET_PPC64) */
+#else /* defined(CONFIG_USER_ONLY) */
+#if defined(TARGET_PPC64)
+#define OP_SPE_LD_TABLE(name) \
+static GenOpFunc *gen_op_spe_l##name[] = { \
+ &gen_op_spe_l##name##_user, \
+ &gen_op_spe_l##name##_le_user, \
+ &gen_op_spe_l##name##_kernel, \
+ &gen_op_spe_l##name##_le_kernel, \
+ &gen_op_spe_l##name##_64_user, \
+ &gen_op_spe_l##name##_le_64_user, \
+ &gen_op_spe_l##name##_64_kernel, \
+ &gen_op_spe_l##name##_le_64_kernel, \
+};
+#define OP_SPE_ST_TABLE(name) \
+static GenOpFunc *gen_op_spe_st##name[] = { \
+ &gen_op_spe_st##name##_user, \
+ &gen_op_spe_st##name##_le_user, \
+ &gen_op_spe_st##name##_kernel, \
+ &gen_op_spe_st##name##_le_kernel, \
+ &gen_op_spe_st##name##_64_user, \
+ &gen_op_spe_st##name##_le_64_user, \
+ &gen_op_spe_st##name##_64_kernel, \
+ &gen_op_spe_st##name##_le_64_kernel, \
+};
+#else /* defined(TARGET_PPC64) */
+#define OP_SPE_LD_TABLE(name) \
+static GenOpFunc *gen_op_spe_l##name[] = { \
+ &gen_op_spe_l##name##_user, \
+ &gen_op_spe_l##name##_le_user, \
+ &gen_op_spe_l##name##_kernel, \
+ &gen_op_spe_l##name##_le_kernel, \
+};
+#define OP_SPE_ST_TABLE(name) \
+static GenOpFunc *gen_op_spe_st##name[] = { \
+ &gen_op_spe_st##name##_user, \
+ &gen_op_spe_st##name##_le_user, \
+ &gen_op_spe_st##name##_kernel, \
+ &gen_op_spe_st##name##_le_kernel, \
+};
+#endif /* defined(TARGET_PPC64) */
+#endif /* defined(CONFIG_USER_ONLY) */
+
+#define GEN_SPE_LD(name, sh) \
+static inline void gen_evl##name (DisasContext *ctx) \
+{ \
+ if (unlikely(!ctx->spe_enabled)) { \
+ RET_EXCP(ctx, EXCP_NO_SPE, 0); \
+ return; \
+ } \
+ gen_addr_spe_imm_index(ctx, sh); \
+ op_spe_ldst(spe_l##name); \
+ gen_op_store_T1_gpr64(rD(ctx->opcode)); \
+}
+
+#define GEN_SPE_LDX(name) \
+static inline void gen_evl##name##x (DisasContext *ctx) \
+{ \
+ if (unlikely(!ctx->spe_enabled)) { \
+ RET_EXCP(ctx, EXCP_NO_SPE, 0); \
+ return; \
+ } \
+ gen_addr_reg_index(ctx); \
+ op_spe_ldst(spe_l##name); \
+ gen_op_store_T1_gpr64(rD(ctx->opcode)); \
+}
+
+#define GEN_SPEOP_LD(name, sh) \
+OP_SPE_LD_TABLE(name); \
+GEN_SPE_LD(name, sh); \
+GEN_SPE_LDX(name)
+
+#define GEN_SPE_ST(name, sh) \
+static inline void gen_evst##name (DisasContext *ctx) \
+{ \
+ if (unlikely(!ctx->spe_enabled)) { \
+ RET_EXCP(ctx, EXCP_NO_SPE, 0); \
+ return; \
+ } \
+ gen_addr_spe_imm_index(ctx, sh); \
+ gen_op_load_gpr64_T1(rS(ctx->opcode)); \
+ op_spe_ldst(spe_st##name); \
+}
+
+#define GEN_SPE_STX(name) \
+static inline void gen_evst##name##x (DisasContext *ctx) \
+{ \
+ if (unlikely(!ctx->spe_enabled)) { \
+ RET_EXCP(ctx, EXCP_NO_SPE, 0); \
+ return; \
+ } \
+ gen_addr_reg_index(ctx); \
+ gen_op_load_gpr64_T1(rS(ctx->opcode)); \
+ op_spe_ldst(spe_st##name); \
+}
+
+#define GEN_SPEOP_ST(name, sh) \
+OP_SPE_ST_TABLE(name); \
+GEN_SPE_ST(name, sh); \
+GEN_SPE_STX(name)
+
+#define GEN_SPEOP_LDST(name, sh) \
+GEN_SPEOP_LD(name, sh); \
+GEN_SPEOP_ST(name, sh)
+
+/* SPE arithmetic and logic */
+#define GEN_SPEOP_ARITH2(name) \
+static inline void gen_##name (DisasContext *ctx) \
+{ \
+ if (unlikely(!ctx->spe_enabled)) { \
+ RET_EXCP(ctx, EXCP_NO_SPE, 0); \
+ return; \
+ } \
+ gen_op_load_gpr64_T0(rA(ctx->opcode)); \
+ gen_op_load_gpr64_T1(rB(ctx->opcode)); \
+ gen_op_##name(); \
+ gen_op_store_T0_gpr64(rD(ctx->opcode)); \
+}
+
+#define GEN_SPEOP_ARITH1(name) \
+static inline void gen_##name (DisasContext *ctx) \
+{ \
+ if (unlikely(!ctx->spe_enabled)) { \
+ RET_EXCP(ctx, EXCP_NO_SPE, 0); \
+ return; \
+ } \
+ gen_op_load_gpr64_T0(rA(ctx->opcode)); \
+ gen_op_##name(); \
+ gen_op_store_T0_gpr64(rD(ctx->opcode)); \
+}
+
+#define GEN_SPEOP_COMP(name) \
+static inline void gen_##name (DisasContext *ctx) \
+{ \
+ if (unlikely(!ctx->spe_enabled)) { \
+ RET_EXCP(ctx, EXCP_NO_SPE, 0); \
+ return; \
+ } \
+ gen_op_load_gpr64_T0(rA(ctx->opcode)); \
+ gen_op_load_gpr64_T1(rB(ctx->opcode)); \
+ gen_op_##name(); \
+ gen_op_store_T0_crf(crfD(ctx->opcode)); \
+}
+
+/* Logical */
+GEN_SPEOP_ARITH2(evand);
+GEN_SPEOP_ARITH2(evandc);
+GEN_SPEOP_ARITH2(evxor);
+GEN_SPEOP_ARITH2(evor);
+GEN_SPEOP_ARITH2(evnor);
+GEN_SPEOP_ARITH2(eveqv);
+GEN_SPEOP_ARITH2(evorc);
+GEN_SPEOP_ARITH2(evnand);
+GEN_SPEOP_ARITH2(evsrwu);
+GEN_SPEOP_ARITH2(evsrws);
+GEN_SPEOP_ARITH2(evslw);
+GEN_SPEOP_ARITH2(evrlw);
+GEN_SPEOP_ARITH2(evmergehi);
+GEN_SPEOP_ARITH2(evmergelo);
+GEN_SPEOP_ARITH2(evmergehilo);
+GEN_SPEOP_ARITH2(evmergelohi);
+
+/* Arithmetic */
+GEN_SPEOP_ARITH2(evaddw);
+GEN_SPEOP_ARITH2(evsubfw);
+GEN_SPEOP_ARITH1(evabs);
+GEN_SPEOP_ARITH1(evneg);
+GEN_SPEOP_ARITH1(evextsb);
+GEN_SPEOP_ARITH1(evextsh);
+GEN_SPEOP_ARITH1(evrndw);
+GEN_SPEOP_ARITH1(evcntlzw);
+GEN_SPEOP_ARITH1(evcntlsw);
+static inline void gen_brinc (DisasContext *ctx)
+{
+ /* Note: brinc is usable even if SPE is disabled */
+ gen_op_load_gpr64_T0(rA(ctx->opcode));
+ gen_op_load_gpr64_T1(rB(ctx->opcode));
+ gen_op_brinc();
+ gen_op_store_T0_gpr64(rD(ctx->opcode));
+}
+
+#define GEN_SPEOP_ARITH_IMM2(name) \
+static inline void gen_##name##i (DisasContext *ctx) \
+{ \
+ if (unlikely(!ctx->spe_enabled)) { \
+ RET_EXCP(ctx, EXCP_NO_SPE, 0); \
+ return; \
+ } \
+ gen_op_load_gpr64_T0(rB(ctx->opcode)); \
+ gen_op_splatwi_T1_64(rA(ctx->opcode)); \
+ gen_op_##name(); \
+ gen_op_store_T0_gpr64(rD(ctx->opcode)); \
+}
+
+#define GEN_SPEOP_LOGIC_IMM2(name) \
+static inline void gen_##name##i (DisasContext *ctx) \
+{ \
+ if (unlikely(!ctx->spe_enabled)) { \
+ RET_EXCP(ctx, EXCP_NO_SPE, 0); \
+ return; \
+ } \
+ gen_op_load_gpr64_T0(rA(ctx->opcode)); \
+ gen_op_splatwi_T1_64(rB(ctx->opcode)); \
+ gen_op_##name(); \
+ gen_op_store_T0_gpr64(rD(ctx->opcode)); \
+}
+
+GEN_SPEOP_ARITH_IMM2(evaddw);
+#define gen_evaddiw gen_evaddwi
+GEN_SPEOP_ARITH_IMM2(evsubfw);
+#define gen_evsubifw gen_evsubfwi
+GEN_SPEOP_LOGIC_IMM2(evslw);
+GEN_SPEOP_LOGIC_IMM2(evsrwu);
+#define gen_evsrwis gen_evsrwsi
+GEN_SPEOP_LOGIC_IMM2(evsrws);
+#define gen_evsrwiu gen_evsrwui
+GEN_SPEOP_LOGIC_IMM2(evrlw);
+
+static inline void gen_evsplati (DisasContext *ctx)
+{
+ int32_t imm = (int32_t)(rA(ctx->opcode) << 27) >> 27;
+
+ gen_op_splatwi_T0_64(imm);
+ gen_op_store_T0_gpr64(rD(ctx->opcode));
+}
+
+static inline void gen_evsplatfi (DisasContext *ctx)
+{
+ uint32_t imm = rA(ctx->opcode) << 27;
+
+ gen_op_splatwi_T0_64(imm);
+ gen_op_store_T0_gpr64(rD(ctx->opcode));
+}
+
+/* Comparison */
+GEN_SPEOP_COMP(evcmpgtu);
+GEN_SPEOP_COMP(evcmpgts);
+GEN_SPEOP_COMP(evcmpltu);
+GEN_SPEOP_COMP(evcmplts);
+GEN_SPEOP_COMP(evcmpeq);
+
+GEN_SPE(evaddw, speundef, 0x00, 0x08, 0x00000000, PPC_SPE); ////
+GEN_SPE(evaddiw, speundef, 0x01, 0x08, 0x00000000, PPC_SPE);
+GEN_SPE(evsubfw, speundef, 0x02, 0x08, 0x00000000, PPC_SPE); ////
+GEN_SPE(evsubifw, speundef, 0x03, 0x08, 0x00000000, PPC_SPE);
+GEN_SPE(evabs, evneg, 0x04, 0x08, 0x0000F800, PPC_SPE); ////
+GEN_SPE(evextsb, evextsh, 0x05, 0x08, 0x0000F800, PPC_SPE); ////
+GEN_SPE(evrndw, evcntlzw, 0x06, 0x08, 0x0000F800, PPC_SPE); ////
+GEN_SPE(evcntlsw, brinc, 0x07, 0x08, 0x00000000, PPC_SPE); //
+GEN_SPE(speundef, evand, 0x08, 0x08, 0x00000000, PPC_SPE); ////
+GEN_SPE(evandc, speundef, 0x09, 0x08, 0x00000000, PPC_SPE); ////
+GEN_SPE(evxor, evor, 0x0B, 0x08, 0x00000000, PPC_SPE); ////
+GEN_SPE(evnor, eveqv, 0x0C, 0x08, 0x00000000, PPC_SPE); ////
+GEN_SPE(speundef, evorc, 0x0D, 0x08, 0x00000000, PPC_SPE); ////
+GEN_SPE(evnand, speundef, 0x0F, 0x08, 0x00000000, PPC_SPE); ////
+GEN_SPE(evsrwu, evsrws, 0x10, 0x08, 0x00000000, PPC_SPE); ////
+GEN_SPE(evsrwiu, evsrwis, 0x11, 0x08, 0x00000000, PPC_SPE);
+GEN_SPE(evslw, speundef, 0x12, 0x08, 0x00000000, PPC_SPE); ////
+GEN_SPE(evslwi, speundef, 0x13, 0x08, 0x00000000, PPC_SPE);
+GEN_SPE(evrlw, evsplati, 0x14, 0x08, 0x00000000, PPC_SPE); //
+GEN_SPE(evrlwi, evsplatfi, 0x15, 0x08, 0x00000000, PPC_SPE);
+GEN_SPE(evmergehi, evmergelo, 0x16, 0x08, 0x00000000, PPC_SPE); ////
+GEN_SPE(evmergehilo, evmergelohi, 0x17, 0x08, 0x00000000, PPC_SPE); ////
+GEN_SPE(evcmpgtu, evcmpgts, 0x18, 0x08, 0x00600000, PPC_SPE); ////
+GEN_SPE(evcmpltu, evcmplts, 0x19, 0x08, 0x00600000, PPC_SPE); ////
+GEN_SPE(evcmpeq, speundef, 0x1A, 0x08, 0x00600000, PPC_SPE); ////
+
+static inline void gen_evsel (DisasContext *ctx)
+{
+ if (unlikely(!ctx->spe_enabled)) {
+ RET_EXCP(ctx, EXCP_NO_SPE, 0);
+ return;
+ }
+ gen_op_load_crf_T0(ctx->opcode & 0x7);
+ gen_op_load_gpr64_T0(rA(ctx->opcode));
+ gen_op_load_gpr64_T1(rB(ctx->opcode));
+ gen_op_evsel();
+ gen_op_store_T0_gpr64(rD(ctx->opcode));
+}
+
+GEN_HANDLER(evsel0, 0x04, 0x1c, 0x09, 0x00000000, PPC_SPE)
+{
+ gen_evsel(ctx);
+}
+GEN_HANDLER(evsel1, 0x04, 0x1d, 0x09, 0x00000000, PPC_SPE)
+{
+ gen_evsel(ctx);
+}
+GEN_HANDLER(evsel2, 0x04, 0x1e, 0x09, 0x00000000, PPC_SPE)
+{
+ gen_evsel(ctx);
+}
+GEN_HANDLER(evsel3, 0x04, 0x1f, 0x09, 0x00000000, PPC_SPE)
+{
+ gen_evsel(ctx);
+}
+
+/* Load and stores */
+#if defined(TARGET_PPC64)
+/* In that case, we already have 64 bits load & stores
+ * so, spe_ldd is equivalent to ld and spe_std is equivalent to std
+ */
+#if defined(CONFIG_USER_ONLY)
+#define gen_op_spe_ldd_raw gen_op_ld_raw
+#define gen_op_spe_ldd_64_raw gen_op_ld_64_raw
+#define gen_op_spe_ldd_le_raw gen_op_ld_le_raw
+#define gen_op_spe_ldd_le_64_raw gen_op_ld_le_64_raw
+#define gen_op_spe_stdd_raw gen_op_ld_raw
+#define gen_op_spe_stdd_64_raw gen_op_std_64_raw
+#define gen_op_spe_stdd_le_raw gen_op_std_le_raw
+#define gen_op_spe_stdd_le_64_raw gen_op_std_le_64_raw
+#else /* defined(CONFIG_USER_ONLY) */
+#define gen_op_spe_ldd_kernel gen_op_ld_kernel
+#define gen_op_spe_ldd_64_kernel gen_op_ld_64_kernel
+#define gen_op_spe_ldd_le_kernel gen_op_ld_kernel
+#define gen_op_spe_ldd_le_64_kernel gen_op_ld_64_kernel
+#define gen_op_spe_ldd_user gen_op_ld_user
+#define gen_op_spe_ldd_64_user gen_op_ld_64_user
+#define gen_op_spe_ldd_le_user gen_op_ld_le_user
+#define gen_op_spe_ldd_le_64_user gen_op_ld_le_64_user
+#define gen_op_spe_stdd_kernel gen_op_std_kernel
+#define gen_op_spe_stdd_64_kernel gen_op_std_64_kernel
+#define gen_op_spe_stdd_le_kernel gen_op_std_kernel
+#define gen_op_spe_stdd_le_64_kernel gen_op_std_64_kernel
+#define gen_op_spe_stdd_user gen_op_std_user
+#define gen_op_spe_stdd_64_user gen_op_std_64_user
+#define gen_op_spe_stdd_le_user gen_op_std_le_user
+#define gen_op_spe_stdd_le_64_user gen_op_std_le_64_user
+#endif /* defined(CONFIG_USER_ONLY) */
+#endif /* defined(TARGET_PPC64) */
+GEN_SPEOP_LDST(dd, 3);
+GEN_SPEOP_LDST(dw, 3);
+GEN_SPEOP_LDST(dh, 3);
+GEN_SPEOP_LDST(whe, 2);
+GEN_SPEOP_LD(whou, 2);
+GEN_SPEOP_LD(whos, 2);
+GEN_SPEOP_ST(who, 2);
+
+#if defined(TARGET_PPC64)
+/* In that case, spe_stwwo is equivalent to stw */
+#if defined(CONFIG_USER_ONLY)
+#define gen_op_spe_stwwo_raw gen_op_stw_raw
+#define gen_op_spe_stwwo_le_raw gen_op_stw_le_raw
+#define gen_op_spe_stwwo_64_raw gen_op_stw_64_raw
+#define gen_op_spe_stwwo_le_64_raw gen_op_stw_le_64_raw
+#else
+#define gen_op_spe_stwwo_user gen_op_stw_user
+#define gen_op_spe_stwwo_le_user gen_op_stw_le_user
+#define gen_op_spe_stwwo_64_user gen_op_stw_64_user
+#define gen_op_spe_stwwo_le_64_user gen_op_stw_le_64_user
+#define gen_op_spe_stwwo_kernel gen_op_stw_kernel
+#define gen_op_spe_stwwo_le_kernel gen_op_stw_le_kernel
+#define gen_op_spe_stwwo_64_kernel gen_op_stw_64_kernel
+#define gen_op_spe_stwwo_le_64_kernel gen_op_stw_le_64_kernel
+#endif
+#endif
+#define _GEN_OP_SPE_STWWE(suffix) \
+static inline void gen_op_spe_stwwe_##suffix (void) \
+{ \
+ gen_op_srli32_T1_64(); \
+ gen_op_spe_stwwo_##suffix(); \
+}
+#define _GEN_OP_SPE_STWWE_LE(suffix) \
+static inline void gen_op_spe_stwwe_le_##suffix (void) \
+{ \
+ gen_op_srli32_T1_64(); \
+ gen_op_spe_stwwo_le_##suffix(); \
+}
+#if defined(TARGET_PPC64)
+#define GEN_OP_SPE_STWWE(suffix) \
+_GEN_OP_SPE_STWWE(suffix); \
+_GEN_OP_SPE_STWWE_LE(suffix); \
+static inline void gen_op_spe_stwwe_64_##suffix (void) \
+{ \
+ gen_op_srli32_T1_64(); \
+ gen_op_spe_stwwo_64_##suffix(); \
+} \
+static inline void gen_op_spe_stwwe_le_64_##suffix (void) \
+{ \
+ gen_op_srli32_T1_64(); \
+ gen_op_spe_stwwo_le_64_##suffix(); \
+}
+#else
+#define GEN_OP_SPE_STWWE(suffix) \
+_GEN_OP_SPE_STWWE(suffix); \
+_GEN_OP_SPE_STWWE_LE(suffix)
+#endif
+#if defined(CONFIG_USER_ONLY)
+GEN_OP_SPE_STWWE(raw);
+#else /* defined(CONFIG_USER_ONLY) */
+GEN_OP_SPE_STWWE(kernel);
+GEN_OP_SPE_STWWE(user);
+#endif /* defined(CONFIG_USER_ONLY) */
+GEN_SPEOP_ST(wwe, 2);
+GEN_SPEOP_ST(wwo, 2);
+
+#define GEN_SPE_LDSPLAT(name, op, suffix) \
+static inline void gen_op_spe_l##name##_##suffix (void) \
+{ \
+ gen_op_##op##_##suffix(); \
+ gen_op_splatw_T1_64(); \
+}
+
+#define GEN_OP_SPE_LHE(suffix) \
+static inline void gen_op_spe_lhe_##suffix (void) \
+{ \
+ gen_op_spe_lh_##suffix(); \
+ gen_op_sli16_T1_64(); \
+}
+
+#define GEN_OP_SPE_LHX(suffix) \
+static inline void gen_op_spe_lhx_##suffix (void) \
+{ \
+ gen_op_spe_lh_##suffix(); \
+ gen_op_extsh_T1_64(); \
+}
+
+#if defined(CONFIG_USER_ONLY)
+GEN_OP_SPE_LHE(raw);
+GEN_SPE_LDSPLAT(hhesplat, spe_lhe, raw);
+GEN_OP_SPE_LHE(le_raw);
+GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_raw);
+GEN_SPE_LDSPLAT(hhousplat, spe_lh, raw);
+GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_raw);
+GEN_OP_SPE_LHX(raw);
+GEN_SPE_LDSPLAT(hhossplat, spe_lhx, raw);
+GEN_OP_SPE_LHX(le_raw);
+GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_raw);
+#if defined(TARGET_PPC64)
+GEN_OP_SPE_LHE(64_raw);
+GEN_SPE_LDSPLAT(hhesplat, spe_lhe, 64_raw);
+GEN_OP_SPE_LHE(le_64_raw);
+GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_64_raw);
+GEN_SPE_LDSPLAT(hhousplat, spe_lh, 64_raw);
+GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_64_raw);
+GEN_OP_SPE_LHX(64_raw);
+GEN_SPE_LDSPLAT(hhossplat, spe_lhx, 64_raw);
+GEN_OP_SPE_LHX(le_64_raw);
+GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_64_raw);
+#endif
+#else
+GEN_OP_SPE_LHE(kernel);
+GEN_OP_SPE_LHE(user);
+GEN_SPE_LDSPLAT(hhesplat, spe_lhe, kernel);
+GEN_SPE_LDSPLAT(hhesplat, spe_lhe, user);
+GEN_OP_SPE_LHE(le_kernel);
+GEN_OP_SPE_LHE(le_user);
+GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_kernel);
+GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_user);
+GEN_SPE_LDSPLAT(hhousplat, spe_lh, kernel);
+GEN_SPE_LDSPLAT(hhousplat, spe_lh, user);
+GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_kernel);
+GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_user);
+GEN_OP_SPE_LHX(kernel);
+GEN_OP_SPE_LHX(user);
+GEN_SPE_LDSPLAT(hhossplat, spe_lhx, kernel);
+GEN_SPE_LDSPLAT(hhossplat, spe_lhx, user);
+GEN_OP_SPE_LHX(le_kernel);
+GEN_OP_SPE_LHX(le_user);
+GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_kernel);
+GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_user);
+#if defined(TARGET_PPC64)
+GEN_OP_SPE_LHE(64_kernel);
+GEN_OP_SPE_LHE(64_user);
+GEN_SPE_LDSPLAT(hhesplat, spe_lhe, 64_kernel);
+GEN_SPE_LDSPLAT(hhesplat, spe_lhe, 64_user);
+GEN_OP_SPE_LHE(le_64_kernel);
+GEN_OP_SPE_LHE(le_64_user);
+GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_64_kernel);
+GEN_SPE_LDSPLAT(hhesplat, spe_lhe, le_64_user);
+GEN_SPE_LDSPLAT(hhousplat, spe_lh, 64_kernel);
+GEN_SPE_LDSPLAT(hhousplat, spe_lh, 64_user);
+GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_64_kernel);
+GEN_SPE_LDSPLAT(hhousplat, spe_lh, le_64_user);
+GEN_OP_SPE_LHX(64_kernel);
+GEN_OP_SPE_LHX(64_user);
+GEN_SPE_LDSPLAT(hhossplat, spe_lhx, 64_kernel);
+GEN_SPE_LDSPLAT(hhossplat, spe_lhx, 64_user);
+GEN_OP_SPE_LHX(le_64_kernel);
+GEN_OP_SPE_LHX(le_64_user);
+GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_64_kernel);
+GEN_SPE_LDSPLAT(hhossplat, spe_lhx, le_64_user);
+#endif
+#endif
+GEN_SPEOP_LD(hhesplat, 1);
+GEN_SPEOP_LD(hhousplat, 1);
+GEN_SPEOP_LD(hhossplat, 1);
+GEN_SPEOP_LD(wwsplat, 2);
+GEN_SPEOP_LD(whsplat, 2);
+
+GEN_SPE(evlddx, evldd, 0x00, 0x0C, 0x00000000, PPC_SPE); //
+GEN_SPE(evldwx, evldw, 0x01, 0x0C, 0x00000000, PPC_SPE); //
+GEN_SPE(evldhx, evldh, 0x02, 0x0C, 0x00000000, PPC_SPE); //
+GEN_SPE(evlhhesplatx, evlhhesplat, 0x04, 0x0C, 0x00000000, PPC_SPE); //
+GEN_SPE(evlhhousplatx, evlhhousplat, 0x06, 0x0C, 0x00000000, PPC_SPE); //
+GEN_SPE(evlhhossplatx, evlhhossplat, 0x07, 0x0C, 0x00000000, PPC_SPE); //
+GEN_SPE(evlwhex, evlwhe, 0x08, 0x0C, 0x00000000, PPC_SPE); //
+GEN_SPE(evlwhoux, evlwhou, 0x0A, 0x0C, 0x00000000, PPC_SPE); //
+GEN_SPE(evlwhosx, evlwhos, 0x0B, 0x0C, 0x00000000, PPC_SPE); //
+GEN_SPE(evlwwsplatx, evlwwsplat, 0x0C, 0x0C, 0x00000000, PPC_SPE); //
+GEN_SPE(evlwhsplatx, evlwhsplat, 0x0E, 0x0C, 0x00000000, PPC_SPE); //
+GEN_SPE(evstddx, evstdd, 0x10, 0x0C, 0x00000000, PPC_SPE); //
+GEN_SPE(evstdwx, evstdw, 0x11, 0x0C, 0x00000000, PPC_SPE); //
+GEN_SPE(evstdhx, evstdh, 0x12, 0x0C, 0x00000000, PPC_SPE); //
+GEN_SPE(evstwhex, evstwhe, 0x18, 0x0C, 0x00000000, PPC_SPE); //
+GEN_SPE(evstwhox, evstwho, 0x1A, 0x0C, 0x00000000, PPC_SPE); //
+GEN_SPE(evstwwex, evstwwe, 0x1C, 0x0C, 0x00000000, PPC_SPE); //
+GEN_SPE(evstwwox, evstwwo, 0x1E, 0x0C, 0x00000000, PPC_SPE); //
+
+/* Multiply and add - TODO */
+#if 0
+GEN_SPE(speundef, evmhessf, 0x01, 0x10, 0x00000000, PPC_SPE);
+GEN_SPE(speundef, evmhossf, 0x03, 0x10, 0x00000000, PPC_SPE);
+GEN_SPE(evmheumi, evmhesmi, 0x04, 0x10, 0x00000000, PPC_SPE);
+GEN_SPE(speundef, evmhesmf, 0x05, 0x10, 0x00000000, PPC_SPE);
+GEN_SPE(evmhoumi, evmhosmi, 0x06, 0x10, 0x00000000, PPC_SPE);
+GEN_SPE(speundef, evmhosmf, 0x07, 0x10, 0x00000000, PPC_SPE);
+GEN_SPE(speundef, evmhessfa, 0x11, 0x10, 0x00000000, PPC_SPE);
+GEN_SPE(speundef, evmhossfa, 0x13, 0x10, 0x00000000, PPC_SPE);
+GEN_SPE(evmheumia, evmhesmia, 0x14, 0x10, 0x00000000, PPC_SPE);
+GEN_SPE(speundef, evmhesmfa, 0x15, 0x10, 0x00000000, PPC_SPE);
+GEN_SPE(evmhoumia, evmhosmia, 0x16, 0x10, 0x00000000, PPC_SPE);
+GEN_SPE(speundef, evmhosmfa, 0x17, 0x10, 0x00000000, PPC_SPE);
+
+GEN_SPE(speundef, evmwhssf, 0x03, 0x11, 0x00000000, PPC_SPE);
+GEN_SPE(evmwlumi, speundef, 0x04, 0x11, 0x00000000, PPC_SPE);
+GEN_SPE(evmwhumi, evmwhsmi, 0x06, 0x11, 0x00000000, PPC_SPE);
+GEN_SPE(speundef, evmwhsmf, 0x07, 0x11, 0x00000000, PPC_SPE);
+GEN_SPE(speundef, evmwssf, 0x09, 0x11, 0x00000000, PPC_SPE);
+GEN_SPE(evmwumi, evmwsmi, 0x0C, 0x11, 0x00000000, PPC_SPE);
+GEN_SPE(speundef, evmwsmf, 0x0D, 0x11, 0x00000000, PPC_SPE);
+GEN_SPE(speundef, evmwhssfa, 0x13, 0x11, 0x00000000, PPC_SPE);
+GEN_SPE(evmwlumia, speundef, 0x14, 0x11, 0x00000000, PPC_SPE);
+GEN_SPE(evmwhumia, evmwhsmia, 0x16, 0x11, 0x00000000, PPC_SPE);
+GEN_SPE(speundef, evmwhsmfa, 0x17, 0x11, 0x00000000, PPC_SPE);
+GEN_SPE(speundef, evmwssfa, 0x19, 0x11, 0x00000000, PPC_SPE);
+GEN_SPE(evmwumia, evmwsmia, 0x1C, 0x11, 0x00000000, PPC_SPE);
+GEN_SPE(speundef, evmwsmfa, 0x1D, 0x11, 0x00000000, PPC_SPE);
+
+GEN_SPE(evadduiaaw, evaddsiaaw, 0x00, 0x13, 0x0000F800, PPC_SPE);
+GEN_SPE(evsubfusiaaw, evsubfssiaaw, 0x01, 0x13, 0x0000F800, PPC_SPE);
+GEN_SPE(evaddumiaaw, evaddsmiaaw, 0x04, 0x13, 0x0000F800, PPC_SPE);
+GEN_SPE(evsubfumiaaw, evsubfsmiaaw, 0x05, 0x13, 0x0000F800, PPC_SPE);
+GEN_SPE(evdivws, evdivwu, 0x06, 0x13, 0x00000000, PPC_SPE);
+GEN_SPE(evmra, speundef, 0x07, 0x13, 0x0000F800, PPC_SPE);
+
+GEN_SPE(evmheusiaaw, evmhessiaaw, 0x00, 0x14, 0x00000000, PPC_SPE);
+GEN_SPE(speundef, evmhessfaaw, 0x01, 0x14, 0x00000000, PPC_SPE);
+GEN_SPE(evmhousiaaw, evmhossiaaw, 0x02, 0x14, 0x00000000, PPC_SPE);
+GEN_SPE(speundef, evmhossfaaw, 0x03, 0x14, 0x00000000, PPC_SPE);
+GEN_SPE(evmheumiaaw, evmhesmiaaw, 0x04, 0x14, 0x00000000, PPC_SPE);
+GEN_SPE(speundef, evmhesmfaaw, 0x05, 0x14, 0x00000000, PPC_SPE);
+GEN_SPE(evmhoumiaaw, evmhosmiaaw, 0x06, 0x14, 0x00000000, PPC_SPE);
+GEN_SPE(speundef, evmhosmfaaw, 0x07, 0x14, 0x00000000, PPC_SPE);
+GEN_SPE(evmhegumiaa, evmhegsmiaa, 0x14, 0x14, 0x00000000, PPC_SPE);
+GEN_SPE(speundef, evmhegsmfaa, 0x15, 0x14, 0x00000000, PPC_SPE);
+GEN_SPE(evmhogumiaa, evmhogsmiaa, 0x16, 0x14, 0x00000000, PPC_SPE);
+GEN_SPE(speundef, evmhogsmfaa, 0x17, 0x14, 0x00000000, PPC_SPE);
+
+GEN_SPE(evmwlusiaaw, evmwlssiaaw, 0x00, 0x15, 0x00000000, PPC_SPE);
+GEN_SPE(evmwlumiaaw, evmwlsmiaaw, 0x04, 0x15, 0x00000000, PPC_SPE);
+GEN_SPE(speundef, evmwssfaa, 0x09, 0x15, 0x00000000, PPC_SPE);
+GEN_SPE(evmwumiaa, evmwsmiaa, 0x0C, 0x15, 0x00000000, PPC_SPE);
+GEN_SPE(speundef, evmwsmfaa, 0x0D, 0x15, 0x00000000, PPC_SPE);
+
+GEN_SPE(evmheusianw, evmhessianw, 0x00, 0x16, 0x00000000, PPC_SPE);
+GEN_SPE(speundef, evmhessfanw, 0x01, 0x16, 0x00000000, PPC_SPE);
+GEN_SPE(evmhousianw, evmhossianw, 0x02, 0x16, 0x00000000, PPC_SPE);
+GEN_SPE(speundef, evmhossfanw, 0x03, 0x16, 0x00000000, PPC_SPE);
+GEN_SPE(evmheumianw, evmhesmianw, 0x04, 0x16, 0x00000000, PPC_SPE);
+GEN_SPE(speundef, evmhesmfanw, 0x05, 0x16, 0x00000000, PPC_SPE);
+GEN_SPE(evmhoumianw, evmhosmianw, 0x06, 0x16, 0x00000000, PPC_SPE);
+GEN_SPE(speundef, evmhosmfanw, 0x07, 0x16, 0x00000000, PPC_SPE);
+GEN_SPE(evmhegumian, evmhegsmian, 0x14, 0x16, 0x00000000, PPC_SPE);
+GEN_SPE(speundef, evmhegsmfan, 0x15, 0x16, 0x00000000, PPC_SPE);
+GEN_SPE(evmhigumian, evmhigsmian, 0x16, 0x16, 0x00000000, PPC_SPE);
+GEN_SPE(speundef, evmhogsmfan, 0x17, 0x16, 0x00000000, PPC_SPE);
+
+GEN_SPE(evmwlusianw, evmwlssianw, 0x00, 0x17, 0x00000000, PPC_SPE);
+GEN_SPE(evmwlumianw, evmwlsmianw, 0x04, 0x17, 0x00000000, PPC_SPE);
+GEN_SPE(speundef, evmwssfan, 0x09, 0x17, 0x00000000, PPC_SPE);
+GEN_SPE(evmwumian, evmwsmian, 0x0C, 0x17, 0x00000000, PPC_SPE);
+GEN_SPE(speundef, evmwsmfan, 0x0D, 0x17, 0x00000000, PPC_SPE);
+#endif
+
+/*** SPE floating-point extension ***/
+#define GEN_SPEFPUOP_CONV(name) \
+static inline void gen_##name (DisasContext *ctx) \
+{ \
+ gen_op_load_gpr64_T0(rB(ctx->opcode)); \
+ gen_op_##name(); \
+ gen_op_store_T0_gpr64(rD(ctx->opcode)); \
+}
+
+/* Single precision floating-point vectors operations */
+/* Arithmetic */
+GEN_SPEOP_ARITH2(evfsadd);
+GEN_SPEOP_ARITH2(evfssub);
+GEN_SPEOP_ARITH2(evfsmul);
+GEN_SPEOP_ARITH2(evfsdiv);
+GEN_SPEOP_ARITH1(evfsabs);
+GEN_SPEOP_ARITH1(evfsnabs);
+GEN_SPEOP_ARITH1(evfsneg);
+/* Conversion */
+GEN_SPEFPUOP_CONV(evfscfui);
+GEN_SPEFPUOP_CONV(evfscfsi);
+GEN_SPEFPUOP_CONV(evfscfuf);
+GEN_SPEFPUOP_CONV(evfscfsf);
+GEN_SPEFPUOP_CONV(evfsctui);
+GEN_SPEFPUOP_CONV(evfsctsi);
+GEN_SPEFPUOP_CONV(evfsctuf);
+GEN_SPEFPUOP_CONV(evfsctsf);
+GEN_SPEFPUOP_CONV(evfsctuiz);
+GEN_SPEFPUOP_CONV(evfsctsiz);
+/* Comparison */
+GEN_SPEOP_COMP(evfscmpgt);
+GEN_SPEOP_COMP(evfscmplt);
+GEN_SPEOP_COMP(evfscmpeq);
+GEN_SPEOP_COMP(evfststgt);
+GEN_SPEOP_COMP(evfststlt);
+GEN_SPEOP_COMP(evfststeq);
+
+/* Opcodes definitions */
+GEN_SPE(evfsadd, evfssub, 0x00, 0x0A, 0x00000000, PPC_SPEFPU); //
+GEN_SPE(evfsabs, evfsnabs, 0x02, 0x0A, 0x0000F800, PPC_SPEFPU); //
+GEN_SPE(evfsneg, speundef, 0x03, 0x0A, 0x0000F800, PPC_SPEFPU); //
+GEN_SPE(evfsmul, evfsdiv, 0x04, 0x0A, 0x00000000, PPC_SPEFPU); //
+GEN_SPE(evfscmpgt, evfscmplt, 0x06, 0x0A, 0x00600000, PPC_SPEFPU); //
+GEN_SPE(evfscmpeq, speundef, 0x07, 0x0A, 0x00600000, PPC_SPEFPU); //
+GEN_SPE(evfscfui, evfscfsi, 0x08, 0x0A, 0x00180000, PPC_SPEFPU); //
+GEN_SPE(evfscfuf, evfscfsf, 0x09, 0x0A, 0x00180000, PPC_SPEFPU); //
+GEN_SPE(evfsctui, evfsctsi, 0x0A, 0x0A, 0x00180000, PPC_SPEFPU); //
+GEN_SPE(evfsctuf, evfsctsf, 0x0B, 0x0A, 0x00180000, PPC_SPEFPU); //
+GEN_SPE(evfsctuiz, speundef, 0x0C, 0x0A, 0x00180000, PPC_SPEFPU); //
+GEN_SPE(evfsctsiz, speundef, 0x0D, 0x0A, 0x00180000, PPC_SPEFPU); //
+GEN_SPE(evfststgt, evfststlt, 0x0E, 0x0A, 0x00600000, PPC_SPEFPU); //
+GEN_SPE(evfststeq, speundef, 0x0F, 0x0A, 0x00600000, PPC_SPEFPU); //
+
+/* Single precision floating-point operations */
+/* Arithmetic */
+GEN_SPEOP_ARITH2(efsadd);
+GEN_SPEOP_ARITH2(efssub);
+GEN_SPEOP_ARITH2(efsmul);
+GEN_SPEOP_ARITH2(efsdiv);
+GEN_SPEOP_ARITH1(efsabs);
+GEN_SPEOP_ARITH1(efsnabs);
+GEN_SPEOP_ARITH1(efsneg);
+/* Conversion */
+GEN_SPEFPUOP_CONV(efscfui);
+GEN_SPEFPUOP_CONV(efscfsi);
+GEN_SPEFPUOP_CONV(efscfuf);
+GEN_SPEFPUOP_CONV(efscfsf);
+GEN_SPEFPUOP_CONV(efsctui);
+GEN_SPEFPUOP_CONV(efsctsi);
+GEN_SPEFPUOP_CONV(efsctuf);
+GEN_SPEFPUOP_CONV(efsctsf);
+GEN_SPEFPUOP_CONV(efsctuiz);
+GEN_SPEFPUOP_CONV(efsctsiz);
+GEN_SPEFPUOP_CONV(efscfd);
+/* Comparison */
+GEN_SPEOP_COMP(efscmpgt);
+GEN_SPEOP_COMP(efscmplt);
+GEN_SPEOP_COMP(efscmpeq);
+GEN_SPEOP_COMP(efststgt);
+GEN_SPEOP_COMP(efststlt);
+GEN_SPEOP_COMP(efststeq);
+
+/* Opcodes definitions */
+GEN_SPE(efsadd, efssub, 0x00, 0x0A, 0x00000000, PPC_SPEFPU); //
+GEN_SPE(efsabs, efsnabs, 0x02, 0x0B, 0x0000F800, PPC_SPEFPU); //
+GEN_SPE(efsneg, speundef, 0x03, 0x0B, 0x0000F800, PPC_SPEFPU); //
+GEN_SPE(efsmul, efsdiv, 0x04, 0x0B, 0x00000000, PPC_SPEFPU); //
+GEN_SPE(efscmpgt, efscmplt, 0x06, 0x0B, 0x00600000, PPC_SPEFPU); //
+GEN_SPE(efscmpeq, efscfd, 0x07, 0x0B, 0x00600000, PPC_SPEFPU); //
+GEN_SPE(efscfui, efscfsi, 0x08, 0x0B, 0x00180000, PPC_SPEFPU); //
+GEN_SPE(efscfuf, efscfsf, 0x09, 0x0B, 0x00180000, PPC_SPEFPU); //
+GEN_SPE(efsctui, efsctsi, 0x0A, 0x0B, 0x00180000, PPC_SPEFPU); //
+GEN_SPE(efsctuf, efsctsf, 0x0B, 0x0B, 0x00180000, PPC_SPEFPU); //
+GEN_SPE(efsctuiz, efsctsiz, 0x0C, 0x0B, 0x00180000, PPC_SPEFPU); //
+GEN_SPE(efststgt, efststlt, 0x0E, 0x0B, 0x00600000, PPC_SPEFPU); //
+GEN_SPE(efststeq, speundef, 0x0F, 0x0B, 0x00600000, PPC_SPEFPU); //
+
+/* Double precision floating-point operations */
+/* Arithmetic */
+GEN_SPEOP_ARITH2(efdadd);
+GEN_SPEOP_ARITH2(efdsub);
+GEN_SPEOP_ARITH2(efdmul);
+GEN_SPEOP_ARITH2(efddiv);
+GEN_SPEOP_ARITH1(efdabs);
+GEN_SPEOP_ARITH1(efdnabs);
+GEN_SPEOP_ARITH1(efdneg);
+/* Conversion */
+
+GEN_SPEFPUOP_CONV(efdcfui);
+GEN_SPEFPUOP_CONV(efdcfsi);
+GEN_SPEFPUOP_CONV(efdcfuf);
+GEN_SPEFPUOP_CONV(efdcfsf);
+GEN_SPEFPUOP_CONV(efdctui);
+GEN_SPEFPUOP_CONV(efdctsi);
+GEN_SPEFPUOP_CONV(efdctuf);
+GEN_SPEFPUOP_CONV(efdctsf);
+GEN_SPEFPUOP_CONV(efdctuiz);
+GEN_SPEFPUOP_CONV(efdctsiz);
+GEN_SPEFPUOP_CONV(efdcfs);
+GEN_SPEFPUOP_CONV(efdcfuid);
+GEN_SPEFPUOP_CONV(efdcfsid);
+GEN_SPEFPUOP_CONV(efdctuidz);
+GEN_SPEFPUOP_CONV(efdctsidz);
+/* Comparison */
+GEN_SPEOP_COMP(efdcmpgt);
+GEN_SPEOP_COMP(efdcmplt);
+GEN_SPEOP_COMP(efdcmpeq);
+GEN_SPEOP_COMP(efdtstgt);
+GEN_SPEOP_COMP(efdtstlt);
+GEN_SPEOP_COMP(efdtsteq);
+
+/* Opcodes definitions */
+GEN_SPE(efdadd, efdsub, 0x10, 0x0B, 0x00000000, PPC_SPEFPU); //
+GEN_SPE(efdcfuid, efdcfsid, 0x11, 0x0B, 0x00180000, PPC_SPEFPU); //
+GEN_SPE(efdabs, efdnabs, 0x12, 0x0B, 0x0000F800, PPC_SPEFPU); //
+GEN_SPE(efdneg, speundef, 0x13, 0x0B, 0x0000F800, PPC_SPEFPU); //
+GEN_SPE(efdmul, efddiv, 0x14, 0x0B, 0x00000000, PPC_SPEFPU); //
+GEN_SPE(efdctuidz, efdctsidz, 0x15, 0x0B, 0x00180000, PPC_SPEFPU); //
+GEN_SPE(efdcmpgt, efdcmplt, 0x16, 0x0B, 0x00600000, PPC_SPEFPU); //
+GEN_SPE(efdcmpeq, efdcfs, 0x17, 0x0B, 0x00600000, PPC_SPEFPU); //
+GEN_SPE(efdcfui, efdcfsi, 0x18, 0x0B, 0x00180000, PPC_SPEFPU); //
+GEN_SPE(efdcfuf, efdcfsf, 0x19, 0x0B, 0x00180000, PPC_SPEFPU); //
+GEN_SPE(efdctui, efdctsi, 0x1A, 0x0B, 0x00180000, PPC_SPEFPU); //
+GEN_SPE(efdctuf, efdctsf, 0x1B, 0x0B, 0x00180000, PPC_SPEFPU); //
+GEN_SPE(efdctuiz, speundef, 0x1C, 0x0B, 0x00180000, PPC_SPEFPU); //
+GEN_SPE(efdctsiz, speundef, 0x1D, 0x0B, 0x00180000, PPC_SPEFPU); //
+GEN_SPE(efdtstgt, efdtstlt, 0x1E, 0x0B, 0x00600000, PPC_SPEFPU); //
+GEN_SPE(efdtsteq, speundef, 0x1F, 0x0B, 0x00600000, PPC_SPEFPU); //
+#endif
+
/* End opcode list */
GEN_OPCODE_MARK(end);
@@ -2439,50 +5576,70 @@
/*****************************************************************************/
/* Misc PowerPC helpers */
+static inline uint32_t load_xer (CPUState *env)
+{
+ return (xer_so << XER_SO) |
+ (xer_ov << XER_OV) |
+ (xer_ca << XER_CA) |
+ (xer_bc << XER_BC) |
+ (xer_cmp << XER_CMP);
+}
+
void cpu_dump_state(CPUState *env, FILE *f,
int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
int flags)
{
#if defined(TARGET_PPC64) || 1
#define FILL ""
-#define REGX "%016" PRIx64
#define RGPL 4
#define RFPL 4
#else
#define FILL " "
-#define REGX "%08" PRIx64
#define RGPL 8
#define RFPL 4
#endif
int i;
- cpu_fprintf(f, "NIP " REGX " LR " REGX " CTR " REGX "\n",
+ cpu_fprintf(f, "NIP " ADDRX " LR " ADDRX " CTR " ADDRX "\n",
env->nip, env->lr, env->ctr);
- cpu_fprintf(f, "MSR " REGX FILL " XER %08x TB %08x %08x DECR %08x\n",
- do_load_msr(env), do_load_xer(env), cpu_ppc_load_tbu(env),
- cpu_ppc_load_tbl(env), cpu_ppc_load_decr(env));
- for (i = 0; i < 32; i++) {
+ cpu_fprintf(f, "MSR " REGX FILL " XER %08x "
+#if !defined(NO_TIMER_DUMP)
+ "TB %08x %08x "
+#if !defined(CONFIG_USER_ONLY)
+ "DECR %08x"
+#endif
+#endif
+ "\n",
+ do_load_msr(env), load_xer(env)
+#if !defined(NO_TIMER_DUMP)
+ , cpu_ppc_load_tbu(env), cpu_ppc_load_tbl(env)
+#if !defined(CONFIG_USER_ONLY)
+ , cpu_ppc_load_decr(env)
+#endif
+#endif
+ );
+ for (i = 0; i < 32; i++) {
if ((i & (RGPL - 1)) == 0)
cpu_fprintf(f, "GPR%02d", i);
cpu_fprintf(f, " " REGX, env->gpr[i]);
if ((i & (RGPL - 1)) == (RGPL - 1))
cpu_fprintf(f, "\n");
- }
+ }
cpu_fprintf(f, "CR ");
- for (i = 0; i < 8; i++)
+ for (i = 0; i < 8; i++)
cpu_fprintf(f, "%01x", env->crf[i]);
cpu_fprintf(f, " [");
- for (i = 0; i < 8; i++) {
- char a = '-';
- if (env->crf[i] & 0x08)
- a = 'L';
- else if (env->crf[i] & 0x04)
- a = 'G';
- else if (env->crf[i] & 0x02)
- a = 'E';
+ for (i = 0; i < 8; i++) {
+ char a = '-';
+ if (env->crf[i] & 0x08)
+ a = 'L';
+ else if (env->crf[i] & 0x04)
+ a = 'G';
+ else if (env->crf[i] & 0x02)
+ a = 'E';
cpu_fprintf(f, " %c%c", a, env->crf[i] & 0x01 ? 'O' : ' ');
- }
+ }
cpu_fprintf(f, " ] " FILL "RES " REGX "\n", env->reserve);
for (i = 0; i < 32; i++) {
if ((i & (RFPL - 1)) == 0)
@@ -2495,15 +5652,62 @@
"SDR1 " REGX "\n",
env->spr[SPR_SRR0], env->spr[SPR_SRR1], env->sdr1);
-#undef REGX
#undef RGPL
#undef RFPL
#undef FILL
}
+void cpu_dump_statistics (CPUState *env, FILE*f,
+ int (*cpu_fprintf)(FILE *f, const char *fmt, ...),
+ int flags)
+{
+#if defined(DO_PPC_STATISTICS)
+ opc_handler_t **t1, **t2, **t3, *handler;
+ int op1, op2, op3;
+
+ t1 = env->opcodes;
+ for (op1 = 0; op1 < 64; op1++) {
+ handler = t1[op1];
+ if (is_indirect_opcode(handler)) {
+ t2 = ind_table(handler);
+ for (op2 = 0; op2 < 32; op2++) {
+ handler = t2[op2];
+ if (is_indirect_opcode(handler)) {
+ t3 = ind_table(handler);
+ for (op3 = 0; op3 < 32; op3++) {
+ handler = t3[op3];
+ if (handler->count == 0)
+ continue;
+ cpu_fprintf(f, "%02x %02x %02x (%02x %04d) %16s: "
+ "%016llx %lld\n",
+ op1, op2, op3, op1, (op3 << 5) | op2,
+ handler->oname,
+ handler->count, handler->count);
+ }
+ } else {
+ if (handler->count == 0)
+ continue;
+ cpu_fprintf(f, "%02x %02x (%02x %04d) %16s: "
+ "%016llx %lld\n",
+ op1, op2, op1, op2, handler->oname,
+ handler->count, handler->count);
+ }
+ }
+ } else {
+ if (handler->count == 0)
+ continue;
+ cpu_fprintf(f, "%02x (%02x ) %16s: %016llx %lld\n",
+ op1, op1, handler->oname,
+ handler->count, handler->count);
+ }
+ }
+#endif
+}
+
/*****************************************************************************/
-int gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
- int search_pc)
+static inline int gen_intermediate_code_internal (CPUState *env,
+ TranslationBlock *tb,
+ int search_pc)
{
DisasContext ctx, *ctxp = &ctx;
opc_handler_t **table, *handler;
@@ -2522,11 +5726,23 @@
ctx.spr_cb = env->spr_cb;
#if defined(CONFIG_USER_ONLY)
ctx.mem_idx = msr_le;
+#if defined(TARGET_PPC64)
+ ctx.mem_idx |= msr_sf << 1;
+#endif
#else
ctx.supervisor = 1 - msr_pr;
ctx.mem_idx = ((1 - msr_pr) << 1) | msr_le;
+#if defined(TARGET_PPC64)
+ ctx.mem_idx |= msr_sf << 2;
#endif
+#endif
+#if defined(TARGET_PPC64)
+ ctx.sf_mode = msr_sf;
+#endif
ctx.fpu_enabled = msr_fp;
+#if defined(TARGET_PPCEMB)
+ ctx.spe_enabled = msr_spe;
+#endif
ctx.singlestep_enabled = env->singlestep_enabled;
#if defined (DO_SINGLE_STEP) && 0
/* Single step trace mode */
@@ -2534,16 +5750,16 @@
#endif
/* Set env in case of segfault during code fetch */
while (ctx.exception == EXCP_NONE && gen_opc_ptr < gen_opc_end) {
- if (env->nb_breakpoints > 0) {
- for(j = 0; j < env->nb_breakpoints; j++) {
+ if (unlikely(env->nb_breakpoints > 0)) {
+ for (j = 0; j < env->nb_breakpoints; j++) {
if (env->breakpoints[j] == ctx.nip) {
- gen_op_update_nip(ctx.nip);
+ gen_update_nip(&ctx, ctx.nip);
gen_op_debug();
break;
}
}
}
- if (search_pc) {
+ if (unlikely(search_pc)) {
j = gen_opc_ptr - gen_opc_buf;
if (lj < j) {
lj++;
@@ -2556,7 +5772,7 @@
#if defined PPC_DEBUG_DISAS
if (loglevel & CPU_LOG_TB_IN_ASM) {
fprintf(logfile, "----------------\n");
- fprintf(logfile, "nip=%08x super=%d ir=%d\n",
+ fprintf(logfile, "nip=" ADDRX " super=%d ir=%d\n",
ctx.nip, 1 - msr_pr, msr_ir);
}
#endif
@@ -2586,61 +5802,65 @@
}
}
/* Is opcode *REALLY* valid ? */
- if (handler->handler == &gen_invalid) {
- if (loglevel > 0) {
- fprintf(logfile, "invalid/unsupported opcode: "
- "%02x - %02x - %02x (%08x) 0x%08x %d\n",
- opc1(ctx.opcode), opc2(ctx.opcode),
+ if (unlikely(handler->handler == &gen_invalid)) {
+ if (loglevel != 0) {
+ fprintf(logfile, "invalid/unsupported opcode: "
+ "%02x - %02x - %02x (%08x) 0x" ADDRX " %d\n",
+ opc1(ctx.opcode), opc2(ctx.opcode),
opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, msr_ir);
} else {
printf("invalid/unsupported opcode: "
- "%02x - %02x - %02x (%08x) 0x%08x %d\n",
+ "%02x - %02x - %02x (%08x) 0x" ADDRX " %d\n",
opc1(ctx.opcode), opc2(ctx.opcode),
opc3(ctx.opcode), ctx.opcode, ctx.nip - 4, msr_ir);
}
- } else {
- if ((ctx.opcode & handler->inval) != 0) {
- if (loglevel > 0) {
+ } else {
+ if (unlikely((ctx.opcode & handler->inval) != 0)) {
+ if (loglevel != 0) {
fprintf(logfile, "invalid bits: %08x for opcode: "
- "%02x -%02x - %02x (0x%08x) (0x%08x)\n",
+ "%02x -%02x - %02x (%08x) 0x" ADDRX "\n",
ctx.opcode & handler->inval, opc1(ctx.opcode),
opc2(ctx.opcode), opc3(ctx.opcode),
ctx.opcode, ctx.nip - 4);
} else {
printf("invalid bits: %08x for opcode: "
- "%02x -%02x - %02x (0x%08x) (0x%08x)\n",
- ctx.opcode & handler->inval, opc1(ctx.opcode),
- opc2(ctx.opcode), opc3(ctx.opcode),
+ "%02x -%02x - %02x (%08x) 0x" ADDRX "\n",
+ ctx.opcode & handler->inval, opc1(ctx.opcode),
+ opc2(ctx.opcode), opc3(ctx.opcode),
ctx.opcode, ctx.nip - 4);
- }
+ }
RET_INVAL(ctxp);
break;
}
}
(*(handler->handler))(&ctx);
+#if defined(DO_PPC_STATISTICS)
+ handler->count++;
+#endif
/* Check trace mode exceptions */
- if ((msr_be && ctx.exception == EXCP_BRANCH) ||
- /* Check in single step trace mode
- * we need to stop except if:
- * - rfi, trap or syscall
- * - first instruction of an exception handler
- */
- (msr_se && (ctx.nip < 0x100 ||
- ctx.nip > 0xF00 ||
- (ctx.nip & 0xFC) != 0x04) &&
- ctx.exception != EXCP_SYSCALL &&
- ctx.exception != EXCP_SYSCALL_USER &&
- ctx.exception != EXCP_TRAP)) {
+#if 0 // XXX: buggy on embedded PowerPC
+ if (unlikely((msr_be && ctx.exception == EXCP_BRANCH) ||
+ /* Check in single step trace mode
+ * we need to stop except if:
+ * - rfi, trap or syscall
+ * - first instruction of an exception handler
+ */
+ (msr_se && (ctx.nip < 0x100 ||
+ ctx.nip > 0xF00 ||
+ (ctx.nip & 0xFC) != 0x04) &&
+ ctx.exception != EXCP_SYSCALL &&
+ ctx.exception != EXCP_SYSCALL_USER &&
+ ctx.exception != EXCP_TRAP))) {
RET_EXCP(ctxp, EXCP_TRACE, 0);
}
-
+#endif
/* if we reach a page boundary or are single stepping, stop
* generation
*/
- if (((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) ||
- (env->singlestep_enabled)) {
+ if (unlikely(((ctx.nip & (TARGET_PAGE_SIZE - 1)) == 0) ||
+ (env->singlestep_enabled))) {
break;
- }
+ }
#if defined (DO_SINGLE_STEP)
break;
#endif
@@ -2648,39 +5868,30 @@
if (ctx.exception == EXCP_NONE) {
gen_goto_tb(&ctx, 0, ctx.nip);
} else if (ctx.exception != EXCP_BRANCH) {
- gen_op_set_T0(0);
+ gen_op_reset_T0();
+ /* Generate the return instruction */
+ gen_op_exit_tb();
}
-#if 1
- /* TO BE FIXED: T0 hasn't got a proper value, which makes tb_add_jump
- * do bad business and then qemu crashes !
- */
- gen_op_set_T0(0);
-#endif
- /* Generate the return instruction */
- gen_op_exit_tb();
*gen_opc_ptr = INDEX_op_end;
- if (search_pc) {
+ if (unlikely(search_pc)) {
j = gen_opc_ptr - gen_opc_buf;
lj++;
while (lj <= j)
gen_opc_instr_start[lj++] = 0;
tb->size = 0;
-#if 0
- if (loglevel > 0) {
- page_dump(logfile);
- }
-#endif
} else {
tb->size = ctx.nip - pc_start;
}
-#ifdef DEBUG_DISAS
+#if defined(DEBUG_DISAS)
if (loglevel & CPU_LOG_TB_CPU) {
fprintf(logfile, "---------------- excp: %04x\n", ctx.exception);
cpu_dump_state(env, logfile, fprintf, 0);
}
if (loglevel & CPU_LOG_TB_IN_ASM) {
+ int flags;
+ flags = msr_le;
fprintf(logfile, "IN: %s\n", lookup_symbol(pc_start));
- target_disas(logfile, pc_start, ctx.nip - pc_start, msr_le);
+ target_disas(logfile, pc_start, ctx.nip - pc_start, flags);
fprintf(logfile, "\n");
}
if (loglevel & CPU_LOG_TB_OP) {
Modified: trunk/src/host/qemu-neo1973/target-ppc/translate_init.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-ppc/translate_init.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/target-ppc/translate_init.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -1,7 +1,7 @@
/*
* PowerPC CPU initialization for qemu.
*
- * Copyright (c) 2003-2005 Jocelyn Mayer
+ * Copyright (c) 2003-2007 Jocelyn Mayer
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -25,21 +25,47 @@
//#define PPC_DUMP_CPU
//#define PPC_DEBUG_SPR
+//#define PPC_DEBUG_IRQ
struct ppc_def_t {
const unsigned char *name;
uint32_t pvr;
uint32_t pvr_mask;
- uint32_t insns_flags;
+ uint64_t insns_flags;
uint32_t flags;
uint64_t msr_mask;
};
+/* For user-mode emulation, we don't emulate any IRQ controller */
+#if defined(CONFIG_USER_ONLY)
+#define PPC_IRQ_INIT_FN(name) \
+static inline void glue(glue(ppc, name),_irq_init) (CPUPPCState *env) \
+{ \
+}
+#else
+#define PPC_IRQ_INIT_FN(name) \
+void glue(glue(ppc, name),_irq_init) (CPUPPCState *env);
+#endif
+PPC_IRQ_INIT_FN(405);
+PPC_IRQ_INIT_FN(6xx);
+PPC_IRQ_INIT_FN(970);
+
/* Generic callbacks:
* do nothing but store/retrieve spr value
*/
+#ifdef PPC_DUMP_SPR_ACCESSES
static void spr_read_generic (void *opaque, int sprn)
{
+ gen_op_load_dump_spr(sprn);
+}
+
+static void spr_write_generic (void *opaque, int sprn)
+{
+ gen_op_store_dump_spr(sprn);
+}
+#else
+static void spr_read_generic (void *opaque, int sprn)
+{
gen_op_load_spr(sprn);
}
@@ -47,8 +73,16 @@
{
gen_op_store_spr(sprn);
}
+#endif
-/* SPR common to all PPC */
+#if !defined(CONFIG_USER_ONLY)
+static void spr_write_clear (void *opaque, int sprn)
+{
+ gen_op_mask_spr(sprn);
+}
+#endif
+
+/* SPR common to all PowerPC */
/* XER */
static void spr_read_xer (void *opaque, int sprn)
{
@@ -93,8 +127,9 @@
gen_op_load_spr(sprn + 0x10);
}
-/* SPR common to all non-embedded PPC (ie not 4xx) */
+/* SPR common to all non-embedded PowerPC */
/* DECR */
+#if !defined(CONFIG_USER_ONLY)
static void spr_read_decr (void *opaque, int sprn)
{
gen_op_load_decr();
@@ -104,29 +139,33 @@
{
gen_op_store_decr();
}
+#endif
-/* SPR common to all non-embedded PPC, except 601 */
+/* SPR common to all non-embedded PowerPC, except 601 */
/* Time base */
static void spr_read_tbl (void *opaque, int sprn)
{
gen_op_load_tbl();
}
-static void spr_write_tbl (void *opaque, int sprn)
+static void spr_read_tbu (void *opaque, int sprn)
{
- gen_op_store_tbl();
+ gen_op_load_tbu();
}
-static void spr_read_tbu (void *opaque, int sprn)
+#if !defined(CONFIG_USER_ONLY)
+static void spr_write_tbl (void *opaque, int sprn)
{
- gen_op_load_tbu();
+ gen_op_store_tbl();
}
static void spr_write_tbu (void *opaque, int sprn)
{
gen_op_store_tbu();
}
+#endif
+#if !defined(CONFIG_USER_ONLY)
/* IBAT0U...IBAT0U */
/* IBAT0L...IBAT7L */
static void spr_read_ibat (void *opaque, int sprn)
@@ -229,11 +268,149 @@
RET_STOP(ctx);
}
+/* 64 bits PowerPC specific SPRs */
+/* ASR */
+#if defined(TARGET_PPC64)
+static void spr_read_asr (void *opaque, int sprn)
+{
+ gen_op_load_asr();
+}
+
+static void spr_write_asr (void *opaque, int sprn)
+{
+ DisasContext *ctx = opaque;
+
+ gen_op_store_asr();
+ RET_STOP(ctx);
+}
+#endif
+#endif /* !defined(CONFIG_USER_ONLY) */
+
+/* PowerPC 601 specific registers */
+/* RTC */
+static void spr_read_601_rtcl (void *opaque, int sprn)
+{
+ gen_op_load_601_rtcl();
+}
+
+static void spr_read_601_rtcu (void *opaque, int sprn)
+{
+ gen_op_load_601_rtcu();
+}
+
+#if !defined(CONFIG_USER_ONLY)
+static void spr_write_601_rtcu (void *opaque, int sprn)
+{
+ gen_op_store_601_rtcu();
+}
+
+static void spr_write_601_rtcl (void *opaque, int sprn)
+{
+ gen_op_store_601_rtcl();
+}
+#endif
+
+/* Unified bats */
+#if !defined(CONFIG_USER_ONLY)
+static void spr_read_601_ubat (void *opaque, int sprn)
+{
+ gen_op_load_601_bat(sprn & 1, (sprn - SPR_IBAT0U) / 2);
+}
+
+static void spr_write_601_ubatu (void *opaque, int sprn)
+{
+ DisasContext *ctx = opaque;
+
+ gen_op_store_601_batu((sprn - SPR_IBAT0U) / 2);
+ RET_STOP(ctx);
+}
+
+static void spr_write_601_ubatl (void *opaque, int sprn)
+{
+ DisasContext *ctx = opaque;
+
+ gen_op_store_601_batl((sprn - SPR_IBAT0L) / 2);
+ RET_STOP(ctx);
+}
+#endif
+
+/* PowerPC 40x specific registers */
+#if !defined(CONFIG_USER_ONLY)
+static void spr_read_40x_pit (void *opaque, int sprn)
+{
+ gen_op_load_40x_pit();
+}
+
+static void spr_write_40x_pit (void *opaque, int sprn)
+{
+ gen_op_store_40x_pit();
+}
+
+static void spr_write_40x_dbcr0 (void *opaque, int sprn)
+{
+ DisasContext *ctx = opaque;
+
+ gen_op_store_40x_dbcr0();
+ /* We must stop translation as we may have rebooted */
+ RET_STOP(ctx);
+}
+
+static void spr_write_40x_sler (void *opaque, int sprn)
+{
+ DisasContext *ctx = opaque;
+
+ gen_op_store_40x_sler();
+ /* We must stop the translation as we may have changed
+ * some regions endianness
+ */
+ RET_STOP(ctx);
+}
+
+static void spr_write_booke_tcr (void *opaque, int sprn)
+{
+ gen_op_store_booke_tcr();
+}
+
+static void spr_write_booke_tsr (void *opaque, int sprn)
+{
+ gen_op_store_booke_tsr();
+}
+#endif
+
+/* PowerPC 403 specific registers */
+/* PBL1 / PBU1 / PBL2 / PBU2 */
+#if !defined(CONFIG_USER_ONLY)
+static void spr_read_403_pbr (void *opaque, int sprn)
+{
+ gen_op_load_403_pb(sprn - SPR_403_PBL1);
+}
+
+static void spr_write_403_pbr (void *opaque, int sprn)
+{
+ DisasContext *ctx = opaque;
+
+ gen_op_store_403_pb(sprn - SPR_403_PBL1);
+ RET_STOP(ctx);
+}
+
static void spr_write_pir (void *opaque, int sprn)
{
gen_op_store_pir();
}
+#endif
+#if defined(CONFIG_USER_ONLY)
+#define spr_register(env, num, name, uea_read, uea_write, \
+ oea_read, oea_write, initial_value) \
+do { \
+ _spr_register(env, num, name, uea_read, uea_write, initial_value); \
+} while (0)
+static inline void _spr_register (CPUPPCState *env, int num,
+ const unsigned char *name,
+ void (*uea_read)(void *opaque, int sprn),
+ void (*uea_write)(void *opaque, int sprn),
+ target_ulong initial_value)
+#else
static inline void spr_register (CPUPPCState *env, int num,
const unsigned char *name,
void (*uea_read)(void *opaque, int sprn),
@@ -241,25 +418,30 @@
void (*oea_read)(void *opaque, int sprn),
void (*oea_write)(void *opaque, int sprn),
target_ulong initial_value)
+#endif
{
ppc_spr_t *spr;
spr = &env->spr_cb[num];
if (spr->name != NULL ||env-> spr[num] != 0x00000000 ||
- spr->uea_read != NULL || spr->uea_write != NULL ||
- spr->oea_read != NULL || spr->oea_write != NULL) {
+#if !defined(CONFIG_USER_ONLY)
+ spr->oea_read != NULL || spr->oea_write != NULL ||
+#endif
+ spr->uea_read != NULL || spr->uea_write != NULL) {
printf("Error: Trying to register SPR %d (%03x) twice !\n", num, num);
exit(1);
}
#if defined(PPC_DEBUG_SPR)
- printf("*** register spr %d (%03x) %s val %08" PRIx64 "\n", num, num, name,
- (unsigned long long)initial_value);
+ printf("*** register spr %d (%03x) %s val " ADDRX "\n", num, num, name,
+ initial_value);
#endif
spr->name = name;
spr->uea_read = uea_read;
spr->uea_write = uea_write;
+#if !defined(CONFIG_USER_ONLY)
spr->oea_read = oea_read;
spr->oea_write = oea_write;
+#endif
env->spr[num] = initial_value;
}
@@ -493,6 +675,70 @@
0x00000000);
}
+/* Softare table search registers */
+static void gen_6xx_7xx_soft_tlb (CPUPPCState *env, int nb_tlbs, int nb_ways)
+{
+ env->nb_tlb = nb_tlbs;
+ env->nb_ways = nb_ways;
+ env->id_tlbs = 1;
+ spr_register(env, SPR_DMISS, "DMISS",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, SPR_NOACCESS,
+ 0x00000000);
+ spr_register(env, SPR_DCMP, "DCMP",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, SPR_NOACCESS,
+ 0x00000000);
+ spr_register(env, SPR_HASH1, "HASH1",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, SPR_NOACCESS,
+ 0x00000000);
+ spr_register(env, SPR_HASH2, "HASH2",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, SPR_NOACCESS,
+ 0x00000000);
+ spr_register(env, SPR_IMISS, "IMISS",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, SPR_NOACCESS,
+ 0x00000000);
+ spr_register(env, SPR_ICMP, "ICMP",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, SPR_NOACCESS,
+ 0x00000000);
+ spr_register(env, SPR_RPA, "RPA",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+}
+
+/* SPR common to MPC755 and G2 */
+static void gen_spr_G2_755 (CPUPPCState *env)
+{
+ /* SGPRs */
+ spr_register(env, SPR_SPRG4, "SPRG4",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_SPRG5, "SPRG5",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_SPRG6, "SPRG6",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_SPRG7, "SPRG7",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* External access control */
+ /* XXX : not implemented */
+ spr_register(env, SPR_EAR, "EAR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+}
+
/* SPR common to all 7xx PowerPC implementations */
static void gen_spr_7xx (CPUPPCState *env)
{
@@ -513,6 +759,11 @@
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_L2CR, "L2CR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
/* Performance monitors */
/* XXX : not implemented */
spr_register(env, SPR_MMCR0, "MMCR0",
@@ -669,7 +920,929 @@
0x00000000);
}
-// XXX: TODO (64 bits PPC sprs)
+/* SPR specific to PowerPC 603 implementation */
+static void gen_spr_603 (CPUPPCState *env)
+{
+ /* External access control */
+ /* XXX : not implemented */
+ spr_register(env, SPR_EAR, "EAR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+}
+
+/* SPR specific to PowerPC G2 implementation */
+static void gen_spr_G2 (CPUPPCState *env)
+{
+ /* Memory base address */
+ /* MBAR */
+ spr_register(env, SPR_MBAR, "MBAR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* System version register */
+ /* SVR */
+ spr_register(env, SPR_SVR, "SVR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, SPR_NOACCESS,
+ 0x00000000);
+ /* Exception processing */
+ spr_register(env, SPR_BOOKE_CSRR0, "CSRR0",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_CSRR1, "CSRR1",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* Breakpoints */
+ /* XXX : not implemented */
+ spr_register(env, SPR_DABR, "DABR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_DABR2, "DABR2",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_IABR, "IABR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_IABR2, "IABR2",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_IBCR, "IBCR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_DBCR, "DBCR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+}
+
+/* SPR specific to PowerPC 602 implementation */
+static void gen_spr_602 (CPUPPCState *env)
+{
+ /* ESA registers */
+ /* XXX : not implemented */
+ spr_register(env, SPR_SER, "SER",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_SEBR, "SEBR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_ESASR, "ESASR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* Floating point status */
+ /* XXX : not implemented */
+ spr_register(env, SPR_SP, "SP",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_LT, "LT",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* Watchdog timer */
+ /* XXX : not implemented */
+ spr_register(env, SPR_TCR, "TCR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* Interrupt base */
+ spr_register(env, SPR_IBR, "IBR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+}
+
+/* SPR specific to PowerPC 601 implementation */
+static void gen_spr_601 (CPUPPCState *env)
+{
+ /* Multiplication/division register */
+ /* MQ */
+ spr_register(env, SPR_MQ, "MQ",
+ &spr_read_generic, &spr_write_generic,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* RTC registers */
+ spr_register(env, SPR_601_RTCU, "RTCU",
+ SPR_NOACCESS, SPR_NOACCESS,
+ SPR_NOACCESS, &spr_write_601_rtcu,
+ 0x00000000);
+ spr_register(env, SPR_601_VRTCU, "RTCU",
+ &spr_read_601_rtcu, SPR_NOACCESS,
+ &spr_read_601_rtcu, SPR_NOACCESS,
+ 0x00000000);
+ spr_register(env, SPR_601_RTCL, "RTCL",
+ SPR_NOACCESS, SPR_NOACCESS,
+ SPR_NOACCESS, &spr_write_601_rtcl,
+ 0x00000000);
+ spr_register(env, SPR_601_VRTCL, "RTCL",
+ &spr_read_601_rtcl, SPR_NOACCESS,
+ &spr_read_601_rtcl, SPR_NOACCESS,
+ 0x00000000);
+ /* Timer */
+#if 0 /* ? */
+ spr_register(env, SPR_601_UDECR, "UDECR",
+ &spr_read_decr, SPR_NOACCESS,
+ &spr_read_decr, SPR_NOACCESS,
+ 0x00000000);
+#endif
+ /* External access control */
+ /* XXX : not implemented */
+ spr_register(env, SPR_EAR, "EAR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* Memory management */
+ spr_register(env, SPR_IBAT0U, "IBAT0U",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_601_ubat, &spr_write_601_ubatu,
+ 0x00000000);
+ spr_register(env, SPR_IBAT0L, "IBAT0L",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_601_ubat, &spr_write_601_ubatl,
+ 0x00000000);
+ spr_register(env, SPR_IBAT1U, "IBAT1U",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_601_ubat, &spr_write_601_ubatu,
+ 0x00000000);
+ spr_register(env, SPR_IBAT1L, "IBAT1L",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_601_ubat, &spr_write_601_ubatl,
+ 0x00000000);
+ spr_register(env, SPR_IBAT2U, "IBAT2U",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_601_ubat, &spr_write_601_ubatu,
+ 0x00000000);
+ spr_register(env, SPR_IBAT2L, "IBAT2L",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_601_ubat, &spr_write_601_ubatl,
+ 0x00000000);
+ spr_register(env, SPR_IBAT3U, "IBAT3U",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_601_ubat, &spr_write_601_ubatu,
+ 0x00000000);
+ spr_register(env, SPR_IBAT3L, "IBAT3L",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_601_ubat, &spr_write_601_ubatl,
+ 0x00000000);
+}
+
+/* PowerPC BookE SPR */
+static void gen_spr_BookE (CPUPPCState *env)
+{
+ /* Processor identification */
+ spr_register(env, SPR_BOOKE_PIR, "PIR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_pir,
+ 0x00000000);
+ /* Interrupt processing */
+ spr_register(env, SPR_BOOKE_CSRR0, "CSRR0",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_CSRR1, "CSRR1",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_DSRR0, "DSRR0",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_DSRR1, "DSRR1",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_MCSRR0, "MCSRR0",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_MCSRR1, "MCSRR1",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* Debug */
+ /* XXX : not implemented */
+ spr_register(env, SPR_BOOKE_IAC1, "IAC1",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_BOOKE_IAC2, "IAC2",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_BOOKE_IAC3, "IAC3",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_BOOKE_IAC4, "IAC4",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_BOOKE_DAC1, "DAC1",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_BOOKE_DAC2, "DAC2",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_BOOKE_DVC1, "DVC1",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_BOOKE_DVC2, "DVC2",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_BOOKE_DBCR0, "DBCR0",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_BOOKE_DBCR1, "DBCR1",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_BOOKE_DBCR2, "DBCR2",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_BOOKE_DBSR, "DBSR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_clear,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_DEAR, "DEAR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_ESR, "ESR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_IVPR, "IVPR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* Exception vectors */
+ spr_register(env, SPR_BOOKE_IVOR0, "IVOR0",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_IVOR1, "IVOR1",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_IVOR2, "IVOR2",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_IVOR3, "IVOR3",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_IVOR4, "IVOR4",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_IVOR5, "IVOR5",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_IVOR6, "IVOR6",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_IVOR7, "IVOR7",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_IVOR8, "IVOR8",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_IVOR9, "IVOR9",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_IVOR10, "IVOR10",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_IVOR11, "IVOR11",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_IVOR12, "IVOR12",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_IVOR13, "IVOR13",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_IVOR14, "IVOR14",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_IVOR15, "IVOR15",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_IVOR32, "IVOR32",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_IVOR33, "IVOR33",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_IVOR34, "IVOR34",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_IVOR35, "IVOR35",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_IVOR36, "IVOR36",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_IVOR37, "IVOR37",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_PID, "PID",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_TCR, "TCR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_booke_tcr,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_TSR, "TSR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_booke_tsr,
+ 0x00000000);
+ /* Timer */
+ spr_register(env, SPR_DECR, "DECR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_decr, &spr_write_decr,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_DECAR, "DECAR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ SPR_NOACCESS, &spr_write_generic,
+ 0x00000000);
+ /* SPRGs */
+ spr_register(env, SPR_USPRG0, "USPRG0",
+ &spr_read_generic, &spr_write_generic,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_SPRG4, "SPRG4",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_USPRG4, "USPRG4",
+ &spr_read_ureg, SPR_NOACCESS,
+ &spr_read_ureg, SPR_NOACCESS,
+ 0x00000000);
+ spr_register(env, SPR_SPRG5, "SPRG5",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_USPRG5, "USPRG5",
+ &spr_read_ureg, SPR_NOACCESS,
+ &spr_read_ureg, SPR_NOACCESS,
+ 0x00000000);
+ spr_register(env, SPR_SPRG6, "SPRG6",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_USPRG6, "USPRG6",
+ &spr_read_ureg, SPR_NOACCESS,
+ &spr_read_ureg, SPR_NOACCESS,
+ 0x00000000);
+ spr_register(env, SPR_SPRG7, "SPRG7",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_USPRG7, "USPRG7",
+ &spr_read_ureg, SPR_NOACCESS,
+ &spr_read_ureg, SPR_NOACCESS,
+ 0x00000000);
+}
+
+/* FSL storage control registers */
+static void gen_spr_BookE_FSL (CPUPPCState *env)
+{
+ /* TLB assist registers */
+ spr_register(env, SPR_BOOKE_MAS0, "MAS0",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_MAS1, "MAS2",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_MAS2, "MAS3",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_MAS3, "MAS4",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_MAS4, "MAS5",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_MAS6, "MAS6",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_BOOKE_MAS7, "MAS7",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ if (env->nb_pids > 1) {
+ spr_register(env, SPR_BOOKE_PID1, "PID1",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ }
+ if (env->nb_pids > 2) {
+ spr_register(env, SPR_BOOKE_PID2, "PID2",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ }
+ spr_register(env, SPR_BOOKE_MMUCFG, "MMUCFG",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, SPR_NOACCESS,
+ 0x00000000); /* TOFIX */
+ spr_register(env, SPR_BOOKE_MMUCSR0, "MMUCSR0",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000); /* TOFIX */
+ switch (env->nb_ways) {
+ case 4:
+ spr_register(env, SPR_BOOKE_TLB3CFG, "TLB3CFG",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, SPR_NOACCESS,
+ 0x00000000); /* TOFIX */
+ /* Fallthru */
+ case 3:
+ spr_register(env, SPR_BOOKE_TLB2CFG, "TLB2CFG",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, SPR_NOACCESS,
+ 0x00000000); /* TOFIX */
+ /* Fallthru */
+ case 2:
+ spr_register(env, SPR_BOOKE_TLB1CFG, "TLB1CFG",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, SPR_NOACCESS,
+ 0x00000000); /* TOFIX */
+ /* Fallthru */
+ case 1:
+ spr_register(env, SPR_BOOKE_TLB0CFG, "TLB0CFG",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, SPR_NOACCESS,
+ 0x00000000); /* TOFIX */
+ /* Fallthru */
+ case 0:
+ default:
+ break;
+ }
+}
+
+/* SPR specific to PowerPC 440 implementation */
+static void gen_spr_440 (CPUPPCState *env)
+{
+ /* Cache control */
+ /* XXX : not implemented */
+ spr_register(env, SPR_440_DNV0, "DNV0",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_440_DNV1, "DNV1",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_440_DNV2, "DNV2",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_440_DNV3, "DNV3",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_440_DVT0, "DVT0",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_440_DVT1, "DVT1",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_440_DVT2, "DVT2",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_440_DVT3, "DVT3",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_440_DVLIM, "DVLIM",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_440_INV0, "INV0",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_440_INV1, "INV1",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_440_INV2, "INV2",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_440_INV3, "INV3",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_440_IVT0, "IVT0",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_440_IVT1, "IVT1",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_440_IVT2, "IVT2",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_440_IVT3, "IVT3",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_440_IVLIM, "IVLIM",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* Cache debug */
+ /* XXX : not implemented */
+ spr_register(env, SPR_BOOKE_DCBTRH, "DCBTRH",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, SPR_NOACCESS,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_BOOKE_DCBTRL, "DCBTRL",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, SPR_NOACCESS,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_BOOKE_ICBDR, "ICBDR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, SPR_NOACCESS,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_BOOKE_ICBTRH, "ICBTRH",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, SPR_NOACCESS,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_BOOKE_ICBTRL, "ICBTRL",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, SPR_NOACCESS,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_440_DBDR, "DBDR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* Processor control */
+ spr_register(env, SPR_4xx_CCR0, "CCR0",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_440_RSTCFG, "RSTCFG",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, SPR_NOACCESS,
+ 0x00000000);
+ /* Storage control */
+ spr_register(env, SPR_440_MMUCR, "MMUCR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+}
+
+/* SPR shared between PowerPC 40x implementations */
+static void gen_spr_40x (CPUPPCState *env)
+{
+ /* Cache */
+ /* XXX : not implemented */
+ spr_register(env, SPR_40x_DCCR, "DCCR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_40x_DCWR, "DCWR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_40x_ICCR, "ICCR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_BOOKE_ICBDR, "ICBDR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, SPR_NOACCESS,
+ 0x00000000);
+ /* Bus access control */
+ spr_register(env, SPR_40x_SGR, "SGR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0xFFFFFFFF);
+ spr_register(env, SPR_40x_ZPR, "ZPR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* MMU */
+ spr_register(env, SPR_40x_PID, "PID",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* Exception */
+ spr_register(env, SPR_40x_DEAR, "DEAR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_40x_ESR, "ESR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_40x_EVPR, "EVPR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_40x_SRR2, "SRR2",
+ &spr_read_generic, &spr_write_generic,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_40x_SRR3, "SRR3",
+ &spr_read_generic, &spr_write_generic,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* Timers */
+ spr_register(env, SPR_40x_PIT, "PIT",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_40x_pit, &spr_write_40x_pit,
+ 0x00000000);
+ spr_register(env, SPR_40x_TCR, "TCR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_booke_tcr,
+ 0x00000000);
+ spr_register(env, SPR_40x_TSR, "TSR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_booke_tsr,
+ 0x00000000);
+ /* Debug interface */
+ /* XXX : not implemented */
+ spr_register(env, SPR_40x_DAC1, "DAC1",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_40x_DAC2, "DAC2",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_40x_DBCR0, "DBCR0",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_40x_dbcr0,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_40x_DBSR, "DBSR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_clear,
+ /* Last reset was system reset */
+ 0x00000300);
+ /* XXX : not implemented */
+ spr_register(env, SPR_40x_IAC1, "IAC1",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_40x_IAC2, "IAC2",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+}
+
+/* SPR specific to PowerPC 405 implementation */
+static void gen_spr_405 (CPUPPCState *env)
+{
+ spr_register(env, SPR_4xx_CCR0, "CCR0",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00700000);
+ /* Debug */
+ /* XXX : not implemented */
+ spr_register(env, SPR_405_DBCR1, "DBCR1",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_405_DVC1, "DVC1",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_405_DVC2, "DVC2",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_405_IAC3, "IAC3",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_405_IAC4, "IAC4",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* Storage control */
+ spr_register(env, SPR_405_SLER, "SLER",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_40x_sler,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_405_SU0R, "SU0R",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* SPRG */
+ spr_register(env, SPR_USPRG0, "USPRG0",
+ &spr_read_ureg, SPR_NOACCESS,
+ &spr_read_ureg, SPR_NOACCESS,
+ 0x00000000);
+ spr_register(env, SPR_SPRG4, "SPRG4",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_USPRG4, "USPRG4",
+ &spr_read_ureg, SPR_NOACCESS,
+ &spr_read_ureg, SPR_NOACCESS,
+ 0x00000000);
+ spr_register(env, SPR_SPRG5, "SPRG5",
+ SPR_NOACCESS, SPR_NOACCESS,
+ spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_USPRG5, "USPRG5",
+ &spr_read_ureg, SPR_NOACCESS,
+ &spr_read_ureg, SPR_NOACCESS,
+ 0x00000000);
+ spr_register(env, SPR_SPRG6, "SPRG6",
+ SPR_NOACCESS, SPR_NOACCESS,
+ spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_USPRG6, "USPRG6",
+ &spr_read_ureg, SPR_NOACCESS,
+ &spr_read_ureg, SPR_NOACCESS,
+ 0x00000000);
+ spr_register(env, SPR_SPRG7, "SPRG7",
+ SPR_NOACCESS, SPR_NOACCESS,
+ spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ spr_register(env, SPR_USPRG7, "USPRG7",
+ &spr_read_ureg, SPR_NOACCESS,
+ &spr_read_ureg, SPR_NOACCESS,
+ 0x00000000);
+}
+
+/* SPR shared between PowerPC 401 & 403 implementations */
+static void gen_spr_401_403 (CPUPPCState *env)
+{
+ /* Time base */
+ spr_register(env, SPR_403_VTBL, "TBL",
+ &spr_read_tbl, SPR_NOACCESS,
+ &spr_read_tbl, SPR_NOACCESS,
+ 0x00000000);
+ spr_register(env, SPR_403_TBL, "TBL",
+ SPR_NOACCESS, SPR_NOACCESS,
+ SPR_NOACCESS, &spr_write_tbl,
+ 0x00000000);
+ spr_register(env, SPR_403_VTBU, "TBU",
+ &spr_read_tbu, SPR_NOACCESS,
+ &spr_read_tbu, SPR_NOACCESS,
+ 0x00000000);
+ spr_register(env, SPR_403_TBU, "TBU",
+ SPR_NOACCESS, SPR_NOACCESS,
+ SPR_NOACCESS, &spr_write_tbu,
+ 0x00000000);
+ /* Debug */
+ /* XXX: not implemented */
+ spr_register(env, SPR_403_CDBCR, "CDBCR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+}
+
+/* SPR specific to PowerPC 403 implementation */
+static void gen_spr_403 (CPUPPCState *env)
+{
+ /* MMU */
+ spr_register(env, SPR_403_PBL1, "PBL1",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_403_pbr, &spr_write_403_pbr,
+ 0x00000000);
+ spr_register(env, SPR_403_PBU1, "PBU1",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_403_pbr, &spr_write_403_pbr,
+ 0x00000000);
+ spr_register(env, SPR_403_PBL2, "PBL2",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_403_pbr, &spr_write_403_pbr,
+ 0x00000000);
+ spr_register(env, SPR_403_PBU2, "PBU2",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_403_pbr, &spr_write_403_pbr,
+ 0x00000000);
+ /* Debug */
+ /* XXX : not implemented */
+ spr_register(env, SPR_40x_DAC2, "DAC2",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_40x_IAC2, "IAC2",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+}
+
+/* SPR specific to PowerPC compression coprocessor extension */
+#if defined (TODO)
+static void gen_spr_compress (CPUPPCState *env)
+{
+ spr_register(env, SPR_401_SKR, "SKR",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+}
+#endif
+
+// XXX: TODO (64 bits PowerPC SPRs)
/*
* ASR => SPR 280 (64 bits)
* FPECR => SPR 1022 (?)
@@ -691,32 +1864,241 @@
static void init_ppc_proc (CPUPPCState *env, ppc_def_t *def)
{
+ env->reserve = -1;
/* Default MMU definitions */
env->nb_BATs = -1;
env->nb_tlb = 0;
env->nb_ways = 0;
/* XXX: missing:
- * 32 bits PPC:
+ * 32 bits PowerPC:
* - MPC5xx(x)
* - MPC8xx(x)
- * - RCPU (MPC5xx)
+ * - RCPU (same as MPC5xx ?)
*/
spr_register(env, SPR_PVR, "PVR",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, SPR_NOACCESS,
def->pvr);
- switch (def->pvr & def->pvr_mask) {
- case CPU_PPC_604: /* PPC 604 */
- case CPU_PPC_604E: /* PPC 604e */
- case CPU_PPC_604R: /* PPC 604r */
+ printf("%s: PVR %08x mask %08x => %08x\n", __func__,
+ def->pvr, def->pvr_mask, def->pvr & def->pvr_mask);
+ switch (def->pvr) {
+ /* Embedded PowerPC from IBM */
+ case CPU_PPC_401A1: /* 401 A1 family */
+ case CPU_PPC_401B2: /* 401 B2 family */
+ case CPU_PPC_401C2: /* 401 C2 family */
+ case CPU_PPC_401D2: /* 401 D2 family */
+ case CPU_PPC_401E2: /* 401 E2 family */
+ case CPU_PPC_401F2: /* 401 F2 family */
+ case CPU_PPC_401G2: /* 401 G2 family */
+ case CPU_PPC_IOP480: /* IOP 480 family */
+ case CPU_PPC_COBRA: /* IBM Processor for Network Resources */
gen_spr_generic(env);
+ gen_spr_40x(env);
+ gen_spr_401_403(env);
+#if defined (TODO)
+ /* XXX: optional ? */
+ gen_spr_compress(env);
+#endif
+ env->nb_BATs = 0;
+ env->nb_tlb = 64;
+ env->nb_ways = 1;
+ env->id_tlbs = 0;
+ /* XXX: TODO: allocate internal IRQ controller */
+ break;
+
+ case CPU_PPC_403GA: /* 403 GA family */
+ case CPU_PPC_403GB: /* 403 GB family */
+ case CPU_PPC_403GC: /* 403 GC family */
+ case CPU_PPC_403GCX: /* 403 GCX family */
+ gen_spr_generic(env);
+ gen_spr_40x(env);
+ gen_spr_401_403(env);
+ gen_spr_403(env);
+ env->nb_BATs = 0;
+ env->nb_tlb = 64;
+ env->nb_ways = 1;
+ env->id_tlbs = 0;
+ /* XXX: TODO: allocate internal IRQ controller */
+ break;
+
+ case CPU_PPC_405CR: /* 405 GP/CR family */
+ case CPU_PPC_405EP: /* 405 EP family */
+ case CPU_PPC_405GPR: /* 405 GPR family */
+ case CPU_PPC_405D2: /* 405 D2 family */
+ case CPU_PPC_405D4: /* 405 D4 family */
+ gen_spr_generic(env);
+ /* Time base */
+ gen_tbl(env);
+ gen_spr_40x(env);
+ gen_spr_405(env);
+ env->nb_BATs = 0;
+ env->nb_tlb = 64;
+ env->nb_ways = 1;
+ env->id_tlbs = 0;
+ /* Allocate hardware IRQ controller */
+ ppc405_irq_init(env);
+ break;
+
+ case CPU_PPC_NPE405H: /* NPe405 H family */
+ case CPU_PPC_NPE405H2:
+ case CPU_PPC_NPE405L: /* Npe405 L family */
+ gen_spr_generic(env);
+ /* Time base */
+ gen_tbl(env);
+ gen_spr_40x(env);
+ gen_spr_405(env);
+ env->nb_BATs = 0;
+ env->nb_tlb = 64;
+ env->nb_ways = 1;
+ env->id_tlbs = 0;
+ /* Allocate hardware IRQ controller */
+ ppc405_irq_init(env);
+ break;
+
+#if defined (TODO)
+ case CPU_PPC_STB01000:
+#endif
+#if defined (TODO)
+ case CPU_PPC_STB01010:
+#endif
+#if defined (TODO)
+ case CPU_PPC_STB0210:
+#endif
+ case CPU_PPC_STB03: /* STB03 family */
+#if defined (TODO)
+ case CPU_PPC_STB043: /* STB043 family */
+#endif
+#if defined (TODO)
+ case CPU_PPC_STB045: /* STB045 family */
+#endif
+ case CPU_PPC_STB25: /* STB25 family */
+#if defined (TODO)
+ case CPU_PPC_STB130: /* STB130 family */
+#endif
+ gen_spr_generic(env);
+ /* Time base */
+ gen_tbl(env);
+ gen_spr_40x(env);
+ gen_spr_405(env);
+ env->nb_BATs = 0;
+ env->nb_tlb = 64;
+ env->nb_ways = 1;
+ env->id_tlbs = 0;
+ /* Allocate hardware IRQ controller */
+ ppc405_irq_init(env);
+ break;
+
+ case CPU_PPC_440EP: /* 440 EP family */
+ case CPU_PPC_440GP: /* 440 GP family */
+ case CPU_PPC_440GX: /* 440 GX family */
+ case CPU_PPC_440GXc: /* 440 GXc family */
+ case CPU_PPC_440GXf: /* 440 GXf family */
+ case CPU_PPC_440SP: /* 440 SP family */
+ case CPU_PPC_440SP2:
+ case CPU_PPC_440SPE: /* 440 SPE family */
+ gen_spr_generic(env);
+ /* Time base */
+ gen_tbl(env);
+ gen_spr_BookE(env);
+ gen_spr_440(env);
+ env->nb_BATs = 0;
+ env->nb_tlb = 64;
+ env->nb_ways = 1;
+ env->id_tlbs = 0;
+ /* XXX: TODO: allocate internal IRQ controller */
+ break;
+
+ /* Embedded PowerPC from Freescale */
+#if defined (TODO)
+ case CPU_PPC_5xx:
+ break;
+#endif
+#if defined (TODO)
+ case CPU_PPC_8xx: /* MPC821 / 823 / 850 / 860 */
+ break;
+#endif
+#if defined (TODO)
+ case CPU_PPC_82xx_HIP3: /* MPC8240 / 8260 */
+ case CPU_PPC_82xx_HIP4: /* MPC8240 / 8260 */
+ break;
+#endif
+#if defined (TODO)
+ case CPU_PPC_827x: /* MPC 827x / 828x */
+ break;
+#endif
+
+ /* XXX: Use MPC8540 PVR to implement a test PowerPC BookE target */
+ case CPU_PPC_e500v110:
+ case CPU_PPC_e500v120:
+ case CPU_PPC_e500v210:
+ case CPU_PPC_e500v220:
+ gen_spr_generic(env);
+ /* Time base */
+ gen_tbl(env);
+ gen_spr_BookE(env);
+ gen_spr_BookE_FSL(env);
+ env->nb_BATs = 0;
+ env->nb_tlb = 64;
+ env->nb_ways = 1;
+ env->id_tlbs = 0;
+ /* XXX: TODO: allocate internal IRQ controller */
+ break;
+
+#if defined (TODO)
+ case CPU_PPC_e600:
+ break;
+#endif
+
+ /* 32 bits PowerPC */
+ case CPU_PPC_601: /* PowerPC 601 */
+ gen_spr_generic(env);
gen_spr_ne_601(env);
+ gen_spr_601(env);
+ /* Hardware implementation registers */
+ /* XXX : not implemented */
+ spr_register(env, SPR_HID0, "HID0",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_HID1, "HID1",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_601_HID2, "HID2",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_601_HID5, "HID5",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+#if 0 /* ? */
+ spr_register(env, SPR_601_HID15, "HID15",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+#endif
+ env->nb_tlb = 64;
+ env->nb_ways = 2;
+ env->id_tlbs = 0;
+ env->id_tlbs = 0;
+ /* XXX: TODO: allocate internal IRQ controller */
+ break;
+
+ case CPU_PPC_602: /* PowerPC 602 */
+ gen_spr_generic(env);
+ gen_spr_ne_601(env);
/* Memory management */
gen_low_BATs(env);
/* Time base */
gen_tbl(env);
- gen_spr_604(env);
- /* Hardware implementation registers */
+ gen_6xx_7xx_soft_tlb(env, 64, 2);
+ gen_spr_602(env);
+ /* hardware implementation registers */
/* XXX : not implemented */
spr_register(env, SPR_HID0, "HID0",
SPR_NOACCESS, SPR_NOACCESS,
@@ -727,23 +2109,87 @@
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
+ /* Allocate hardware IRQ controller */
+ ppc6xx_irq_init(env);
break;
- case CPU_PPC_74x: /* PPC 740 / 750 */
- case CPU_PPC_74xP: /* PPC 740P / 750P */
- case CPU_PPC_750CXE: /* IBM PPC 750cxe */
+ case CPU_PPC_603: /* PowerPC 603 */
+ case CPU_PPC_603E: /* PowerPC 603e */
+ case CPU_PPC_603E7v:
+ case CPU_PPC_603E7v2:
+ case CPU_PPC_603P: /* PowerPC 603p */
+ case CPU_PPC_603R: /* PowerPC 603r */
gen_spr_generic(env);
gen_spr_ne_601(env);
/* Memory management */
gen_low_BATs(env);
/* Time base */
gen_tbl(env);
- gen_spr_7xx(env);
+ gen_6xx_7xx_soft_tlb(env, 64, 2);
+ gen_spr_603(env);
+ /* hardware implementation registers */
/* XXX : not implemented */
- spr_register(env, SPR_L2CR, "L2CR",
+ spr_register(env, SPR_HID0, "HID0",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_HID1, "HID1",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* Allocate hardware IRQ controller */
+ ppc6xx_irq_init(env);
+ break;
+
+ case CPU_PPC_G2: /* PowerPC G2 family */
+ case CPU_PPC_G2H4:
+ case CPU_PPC_G2gp:
+ case CPU_PPC_G2ls:
+ case CPU_PPC_G2LE: /* PowerPC G2LE family */
+ case CPU_PPC_G2LEgp:
+ case CPU_PPC_G2LEls:
+ gen_spr_generic(env);
+ gen_spr_ne_601(env);
+ /* Memory management */
+ gen_low_BATs(env);
+ /* Time base */
+ gen_tbl(env);
+ /* Memory management */
+ gen_high_BATs(env);
+ gen_6xx_7xx_soft_tlb(env, 64, 2);
+ gen_spr_G2_755(env);
+ gen_spr_G2(env);
+ /* Hardware implementation register */
+ /* XXX : not implemented */
+ spr_register(env, SPR_HID0, "HID0",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_HID1, "HID1",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_HID2, "HID2",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* Allocate hardware IRQ controller */
+ ppc6xx_irq_init(env);
+ break;
+
+ case CPU_PPC_604: /* PowerPC 604 */
+ case CPU_PPC_604E: /* PowerPC 604e */
+ case CPU_PPC_604R: /* PowerPC 604r */
+ gen_spr_generic(env);
+ gen_spr_ne_601(env);
+ /* Memory management */
+ gen_low_BATs(env);
+ /* Time base */
+ gen_tbl(env);
+ gen_spr_604(env);
/* Hardware implementation registers */
/* XXX : not implemented */
spr_register(env, SPR_HID0, "HID0",
@@ -755,24 +2201,107 @@
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
+ /* Allocate hardware IRQ controller */
+ ppc6xx_irq_init(env);
break;
- case CPU_PPC_750FX: /* IBM PPC 750 FX */
- case CPU_PPC_750GX: /* IBM PPC 750 GX */
+ case CPU_PPC_74x: /* PowerPC 740 / 750 */
+ case CPU_PPC_740E:
+ case CPU_PPC_750E:
+ case CPU_PPC_74xP: /* PowerPC 740P / 750P */
+ case CPU_PPC_750CXE21: /* IBM PowerPC 750cxe */
+ case CPU_PPC_750CXE22:
+ case CPU_PPC_750CXE23:
+ case CPU_PPC_750CXE24:
+ case CPU_PPC_750CXE24b:
+ case CPU_PPC_750CXE31:
+ case CPU_PPC_750CXE31b:
+ case CPU_PPC_750CXR:
gen_spr_generic(env);
gen_spr_ne_601(env);
/* Memory management */
gen_low_BATs(env);
+ /* Time base */
+ gen_tbl(env);
+ gen_spr_7xx(env);
+ /* Hardware implementation registers */
+ /* XXX : not implemented */
+ spr_register(env, SPR_HID0, "HID0",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_HID1, "HID1",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* Allocate hardware IRQ controller */
+ ppc6xx_irq_init(env);
+ break;
+
+ case CPU_PPC_750FX10: /* IBM PowerPC 750 FX */
+ case CPU_PPC_750FX20:
+ case CPU_PPC_750FX21:
+ case CPU_PPC_750FX22:
+ case CPU_PPC_750FX23:
+ case CPU_PPC_750GX10: /* IBM PowerPC 750 GX */
+ case CPU_PPC_750GX11:
+ case CPU_PPC_750GX12:
+ gen_spr_generic(env);
+ gen_spr_ne_601(env);
+ /* Memory management */
+ gen_low_BATs(env);
/* PowerPC 750fx & 750gx has 8 DBATs and 8 IBATs */
gen_high_BATs(env);
/* Time base */
gen_tbl(env);
gen_spr_7xx(env);
+ /* Hardware implementation registers */
/* XXX : not implemented */
- spr_register(env, SPR_L2CR, "L2CR",
+ spr_register(env, SPR_HID0, "HID0",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_HID1, "HID1",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_750_HID2, "HID2",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* Allocate hardware IRQ controller */
+ ppc6xx_irq_init(env);
+ break;
+
+ case CPU_PPC_755_10: /* PowerPC 755 */
+ case CPU_PPC_755_11:
+ case CPU_PPC_755_20:
+ case CPU_PPC_755D:
+ case CPU_PPC_755E:
+ gen_spr_generic(env);
+ gen_spr_ne_601(env);
+ /* Memory management */
+ gen_low_BATs(env);
+ /* Time base */
+ gen_tbl(env);
+ /* Memory management */
+ gen_high_BATs(env);
+ gen_6xx_7xx_soft_tlb(env, 64, 2);
+ gen_spr_G2_755(env);
+ /* L2 cache control */
+ /* XXX : not implemented */
+ spr_register(env, SPR_ICTC, "ICTC",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_L2PM, "L2PM",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
/* Hardware implementation registers */
/* XXX : not implemented */
spr_register(env, SPR_HID0, "HID0",
@@ -781,22 +2310,130 @@
0x00000000);
/* XXX : not implemented */
spr_register(env, SPR_HID1, "HID1",
- SPR_NOACCESS, SPR_NOACCESS,
+ SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
/* XXX : not implemented */
+ spr_register(env, SPR_HID2, "HID2",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* Allocate hardware IRQ controller */
+ ppc6xx_irq_init(env);
+ break;
+
+#if defined (TODO)
+ /* G4 family */
+ case CPU_PPC_7400: /* PowerPC 7400 */
+ case CPU_PPC_7410C: /* PowerPC 7410 */
+ case CPU_PPC_7410D:
+ case CPU_PPC_7410E:
+ case CPU_PPC_7441: /* PowerPC 7441 */
+ case CPU_PPC_7445: /* PowerPC 7445 */
+ case CPU_PPC_7447: /* PowerPC 7447 */
+ case CPU_PPC_7447A: /* PowerPC 7447A */
+ case CPU_PPC_7448: /* PowerPC 7448 */
+ case CPU_PPC_7450: /* PowerPC 7450 */
+ case CPU_PPC_7450b:
+ case CPU_PPC_7451: /* PowerPC 7451 */
+ case CPU_PPC_7451G:
+ case CPU_PPC_7455: /* PowerPC 7455 */
+ case CPU_PPC_7455F:
+ case CPU_PPC_7455G:
+ case CPU_PPC_7457: /* PowerPC 7457 */
+ case CPU_PPC_7457C:
+ case CPU_PPC_7457A: /* PowerPC 7457A */
+ break;
+#endif
+
+ /* 64 bits PowerPC */
+#if defined (TARGET_PPC64)
+#if defined (TODO)
+ case CPU_PPC_620: /* PowerPC 620 */
+ case CPU_PPC_630: /* PowerPC 630 (Power 3) */
+ case CPU_PPC_631: /* PowerPC 631 (Power 3+) */
+ case CPU_PPC_POWER4: /* Power 4 */
+ case CPU_PPC_POWER4P: /* Power 4+ */
+ case CPU_PPC_POWER5: /* Power 5 */
+ case CPU_PPC_POWER5P: /* Power 5+ */
+#endif
+ break;
+
+ case CPU_PPC_970: /* PowerPC 970 */
+ case CPU_PPC_970FX10: /* PowerPC 970 FX */
+ case CPU_PPC_970FX20:
+ case CPU_PPC_970FX21:
+ case CPU_PPC_970FX30:
+ case CPU_PPC_970FX31:
+ case CPU_PPC_970MP10: /* PowerPC 970 MP */
+ case CPU_PPC_970MP11:
+ gen_spr_generic(env);
+ gen_spr_ne_601(env);
+ /* XXX: not correct */
+ gen_low_BATs(env);
+ /* Time base */
+ gen_tbl(env);
+ gen_spr_7xx(env);
+ /* Hardware implementation registers */
+ /* XXX : not implemented */
+ spr_register(env, SPR_HID0, "HID0",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
+ spr_register(env, SPR_HID1, "HID1",
+ SPR_NOACCESS, SPR_NOACCESS,
+ &spr_read_generic, &spr_write_generic,
+ 0x00000000);
+ /* XXX : not implemented */
spr_register(env, SPR_750_HID2, "HID2",
SPR_NOACCESS, SPR_NOACCESS,
&spr_read_generic, &spr_write_generic,
0x00000000);
+ /* Allocate hardware IRQ controller */
+ ppc970_irq_init(env);
break;
+#if defined (TODO)
+ case CPU_PPC_CELL10: /* Cell family */
+ case CPU_PPC_CELL20:
+ case CPU_PPC_CELL30:
+ case CPU_PPC_CELL31:
+#endif
+ break;
+
+#if defined (TODO)
+ case CPU_PPC_RS64: /* Apache (RS64/A35) */
+ case CPU_PPC_RS64II: /* NorthStar (RS64-II/A50) */
+ case CPU_PPC_RS64III: /* Pulsar (RS64-III) */
+ case CPU_PPC_RS64IV: /* IceStar/IStar/SStar (RS64-IV) */
+#endif
+ break;
+#endif /* defined (TARGET_PPC64) */
+
+#if defined (TODO)
+ /* POWER */
+ case CPU_POWER: /* POWER */
+ case CPU_POWER2: /* POWER2 */
+ break;
+#endif
+
default:
gen_spr_generic(env);
+ /* XXX: TODO: allocate internal IRQ controller */
break;
}
if (env->nb_BATs == -1)
env->nb_BATs = 4;
+ /* Allocate TLBs buffer when needed */
+ if (env->nb_tlb != 0) {
+ int nb_tlb = env->nb_tlb;
+ if (env->id_tlbs != 0)
+ nb_tlb *= 2;
+ env->tlb = qemu_mallocz(nb_tlb * sizeof(ppc_tlb_t));
+ /* Pre-compute some useful values */
+ env->tlb_per_way = env->nb_tlb / env->nb_ways;
+ }
}
#if defined(PPC_DUMP_CPU)
@@ -812,8 +2449,13 @@
for (j = 0; j < 32; j++) {
n = (i << 5) | j;
spr = &env->spr_cb[n];
+#if !defined(CONFIG_USER_ONLY)
sw = spr->oea_write != NULL && spr->oea_write != SPR_NOACCESS;
sr = spr->oea_read != NULL && spr->oea_read != SPR_NOACCESS;
+#else
+ sw = 0;
+ sr = 0;
+#endif
uw = spr->uea_write != NULL && spr->uea_write != SPR_NOACCESS;
ur = spr->uea_read != NULL && spr->uea_read != SPR_NOACCESS;
if (sw || sr || uw || ur) {
@@ -889,7 +2531,7 @@
{
if (insert_in_table(ppc_opcodes, idx, handler) < 0) {
printf("*** ERROR: opcode %02x already assigned in main "
- "opcode table\n", idx);
+ "opcode table\n", idx);
return -1;
}
@@ -903,20 +2545,20 @@
if (table[idx1] == &invalid_handler) {
if (create_new_table(table, idx1) < 0) {
printf("*** ERROR: unable to create indirect table "
- "idx=%02x\n", idx1);
+ "idx=%02x\n", idx1);
return -1;
}
} else {
if (!is_indirect_opcode(table[idx1])) {
printf("*** ERROR: idx %02x already assigned to a direct "
- "opcode\n", idx1);
+ "opcode\n", idx1);
return -1;
}
}
if (handler != NULL &&
insert_in_table(ind_table(table[idx1]), idx2, handler) < 0) {
printf("*** ERROR: opcode %02x already assigned in "
- "opcode table %02x\n", idx2, idx1);
+ "opcode table %02x\n", idx2, idx1);
return -1;
}
@@ -925,7 +2567,7 @@
static int register_ind_insn (opc_handler_t **ppc_opcodes,
unsigned char idx1, unsigned char idx2,
- opc_handler_t *handler)
+ opc_handler_t *handler)
{
int ret;
@@ -936,17 +2578,17 @@
static int register_dblind_insn (opc_handler_t **ppc_opcodes,
unsigned char idx1, unsigned char idx2,
- unsigned char idx3, opc_handler_t *handler)
+ unsigned char idx3, opc_handler_t *handler)
{
if (register_ind_in_table(ppc_opcodes, idx1, idx2, NULL) < 0) {
printf("*** ERROR: unable to join indirect table idx "
- "[%02x-%02x]\n", idx1, idx2);
+ "[%02x-%02x]\n", idx1, idx2);
return -1;
}
if (register_ind_in_table(ind_table(ppc_opcodes[idx1]), idx2, idx3,
handler) < 0) {
printf("*** ERROR: unable to insert opcode "
- "[%02x-%02x-%02x]\n", idx1, idx2, idx3);
+ "[%02x-%02x-%02x]\n", idx1, idx2, idx3);
return -1;
}
@@ -1012,21 +2654,23 @@
fill_new_table(env->opcodes, 0x40);
#if defined(PPC_DUMP_CPU)
- printf("* PPC instructions for PVR %08x: %s\n", def->pvr, def->name);
+ printf("* PowerPC instructions for PVR %08x: %s flags %016" PRIx64
+ " %08x\n",
+ def->pvr, def->name, def->insns_flags, def->flags);
#endif
if (&opc_start < &opc_end) {
- start = &opc_start;
- end = &opc_end;
+ start = &opc_start;
+ end = &opc_end;
} else {
- start = &opc_end;
- end = &opc_start;
+ start = &opc_end;
+ end = &opc_start;
}
for (opc = start + 1; opc != end; opc++) {
if ((opc->handler.type & def->insns_flags) != 0) {
if (register_insn(env->opcodes, opc) < 0) {
- printf("*** ERROR initializing PPC instruction "
- "0x%02x 0x%02x 0x%02x\n", opc->opc1, opc->opc2,
- opc->opc3);
+ printf("*** ERROR initializing PowerPC instruction "
+ "0x%02x 0x%02x 0x%02x\n", opc->opc1, opc->opc2,
+ opc->opc3);
return -1;
}
#if defined(PPC_DUMP_CPU)
@@ -1038,7 +2682,7 @@
} else {
printf(" %02x %02x -- (%2d %4d) : %s\n",
opc->opc1, opc->opc2, opc->opc1, opc->opc2,
- opc->oname);
+ opc->oname);
}
} else {
printf(" %02x %02x %02x (%2d %4d) : %s\n",
@@ -1061,61 +2705,26 @@
{
env->msr_mask = def->msr_mask;
env->flags = def->flags;
- if (create_ppc_opcodes(env, def) < 0) {
- printf("Error creating opcodes table\n");
- fflush(stdout);
- fflush(stderr);
+ if (create_ppc_opcodes(env, def) < 0)
return -1;
- }
init_ppc_proc(env, def);
#if defined(PPC_DUMP_CPU)
dump_sprs(env);
+ if (env->tlb != NULL) {
+ printf("%d %s TLB in %d ways\n", env->nb_tlb,
+ env->id_tlbs ? "splitted" : "merged", env->nb_ways);
+ }
#endif
- fflush(stdout);
- fflush(stderr);
return 0;
}
-CPUPPCState *cpu_ppc_init(void)
-{
- CPUPPCState *env;
-
- env = qemu_mallocz(sizeof(CPUPPCState));
- if (!env)
- return NULL;
- cpu_exec_init(env);
- tlb_flush(env, 1);
-#if defined (DO_SINGLE_STEP) && 0
- /* Single step trace mode */
- msr_se = 1;
- msr_be = 1;
-#endif
- msr_fp = 1; /* Allow floating point exceptions */
- msr_me = 1; /* Allow machine check exceptions */
-#if defined(CONFIG_USER_ONLY)
- msr_pr = 1;
-#else
- env->nip = 0xFFFFFFFC;
-#endif
- do_compute_hflags(env);
- env->reserve = -1;
- return env;
-}
-
-void cpu_ppc_close(CPUPPCState *env)
-{
- /* Should also remove all opcode tables... */
- free(env);
-}
-
/*****************************************************************************/
/* PowerPC CPU definitions */
-static ppc_def_t ppc_defs[] =
-{
- /* Embedded PPC */
+static ppc_def_t ppc_defs[] = {
+ /* Embedded PowerPC */
#if defined (TODO)
- /* PPC 401 */
+ /* PowerPC 401 */
{
.name = "401",
.pvr = CPU_PPC_401,
@@ -1137,124 +2746,158 @@
},
#endif
#if defined (TODO)
- /* PPC 403 GA */
+ /* IBM Processor for Network Resources */
{
+ .name = "Cobra",
+ .pvr = CPU_PPC_COBRA,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_401,
+ .flags = PPC_FLAGS_401,
+ .msr_mask = xxx,
+ },
+#endif
+#if defined (TODO)
+ /* Generic PowerPC 403 */
+ {
+ .name = "403",
+ .pvr = CPU_PPC_403,
+ .pvr_mask = 0xFFFFFF00,
+ .insns_flags = PPC_INSNS_403,
+ .flags = PPC_FLAGS_403,
+ .msr_mask = 0x000000000007D23DULL,
+ },
+#endif
+#if defined (TODO)
+ /* PowerPC 403 GA */
+ {
.name = "403ga",
.pvr = CPU_PPC_403GA,
.pvr_mask = 0xFFFFFF00,
.insns_flags = PPC_INSNS_403,
.flags = PPC_FLAGS_403,
- .msr_mask = 0x000000000007D23D,
+ .msr_mask = 0x000000000007D23DULL,
},
#endif
#if defined (TODO)
- /* PPC 403 GB */
+ /* PowerPC 403 GB */
{
.name = "403gb",
.pvr = CPU_PPC_403GB,
.pvr_mask = 0xFFFFFF00,
.insns_flags = PPC_INSNS_403,
.flags = PPC_FLAGS_403,
- .msr_mask = 0x000000000007D23D,
+ .msr_mask = 0x000000000007D23DULL,
},
#endif
#if defined (TODO)
- /* PPC 403 GC */
+ /* PowerPC 403 GC */
{
.name = "403gc",
.pvr = CPU_PPC_403GC,
.pvr_mask = 0xFFFFFF00,
.insns_flags = PPC_INSNS_403,
.flags = PPC_FLAGS_403,
- .msr_mask = 0x000000000007D23D,
+ .msr_mask = 0x000000000007D23DULL,
},
#endif
#if defined (TODO)
- /* PPC 403 GCX */
+ /* PowerPC 403 GCX */
{
.name = "403gcx",
.pvr = CPU_PPC_403GCX,
.pvr_mask = 0xFFFFFF00,
.insns_flags = PPC_INSNS_403,
.flags = PPC_FLAGS_403,
- .msr_mask = 0x000000000007D23D,
+ .msr_mask = 0x000000000007D23DULL,
},
#endif
-#if defined (TODO)
- /* PPC 405 CR */
+ /* Generic PowerPC 405 */
{
- .name = "405cr",
+ .name = "405",
.pvr = CPU_PPC_405,
.pvr_mask = 0xFFFF0000,
.insns_flags = PPC_INSNS_405,
.flags = PPC_FLAGS_405,
- .msr_mask = 0x00000000020EFF30,
+ .msr_mask = 0x00000000020EFF30ULL,
},
-#endif
+ /* PowerPC 405 CR */
+ {
+ .name = "405cr",
+ .pvr = CPU_PPC_405,
+ .pvr_mask = 0xFFFFFFFF,
+ .insns_flags = PPC_INSNS_405,
+ .flags = PPC_FLAGS_405,
+ .msr_mask = 0x00000000020EFF30ULL,
+ },
#if defined (TODO)
- /* PPC 405 GP */
+ /* PowerPC 405 GP */
{
.name = "405gp",
.pvr = CPU_PPC_405,
- .pvr_mask = 0xFFFF0000,
+ .pvr_mask = 0xFFFFFFFF,
.insns_flags = PPC_INSNS_405,
.flags = PPC_FLAGS_405,
- .msr_mask = 0x00000000020EFF30,
+ .msr_mask = 0x00000000020EFF30ULL,
},
#endif
-#if defined (TODO)
- /* PPC 405 EP */
+ /* PowerPC 405 EP */
{
.name = "405ep",
.pvr = CPU_PPC_405EP,
- .pvr_mask = 0xFFFF0000,
+ .pvr_mask = 0xFFFFFFFF,
.insns_flags = PPC_INSNS_405,
.flags = PPC_FLAGS_405,
- .msr_mask = 0x00000000020EFF30,
+ .msr_mask = 0x00000000000ED630ULL,
},
+#if defined (TODO)
+ /* PowerPC 405 EZ */
+ {
+ .name = "405ez",
+ .pvr = CPU_PPC_405EZ,
+ .pvr_mask = 0xFFFFFFFF,
+ .insns_flags = PPC_INSNS_405,
+ .flags = PPC_FLAGS_405,
+ .msr_mask = 0x00000000020EFF30ULL,
+ },
#endif
#if defined (TODO)
- /* PPC 405 GPR */
+ /* PowerPC 405 GPR */
{
.name = "405gpr",
.pvr = CPU_PPC_405GPR,
- .pvr_mask = 0xFFFF0000,
+ .pvr_mask = 0xFFFFFFFF,
.insns_flags = PPC_INSNS_405,
.flags = PPC_FLAGS_405,
- .msr_mask = 0x00000000020EFF30,
+ .msr_mask = 0x00000000020EFF30ULL,
},
#endif
-#if defined (TODO)
- /* PPC 405 D2 */
+ /* PowerPC 405 D2 */
{
.name = "405d2",
.pvr = CPU_PPC_405D2,
- .pvr_mask = 0xFFFF0000,
+ .pvr_mask = 0xFFFFFFFF,
.insns_flags = PPC_INSNS_405,
.flags = PPC_FLAGS_405,
- .msr_mask = 0x00000000020EFF30,
+ .msr_mask = 0x00000000020EFF30ULL,
},
-#endif
-#if defined (TODO)
- /* PPC 405 D4 */
+ /* PowerPC 405 D4 */
{
.name = "405d4",
.pvr = CPU_PPC_405D4,
- .pvr_mask = 0xFFFF0000,
+ .pvr_mask = 0xFFFFFFFF,
.insns_flags = PPC_INSNS_405,
.flags = PPC_FLAGS_405,
- .msr_mask = 0x00000000020EFF30,
+ .msr_mask = 0x00000000020EFF30ULL,
},
-#endif
#if defined (TODO)
/* Npe405 H */
{
.name = "Npe405H",
.pvr = CPU_PPC_NPE405H,
- .pvr_mask = 0xFFFF0000,
- .insns_flags = PPC_INSNS_405,
+ .pvr_mask = 0xFFFFFFFF,
+ .insns_flags = PPC_INSNS_405,
.flags = PPC_FLAGS_405,
- .msr_mask = 0x00000000020EFF30,
+ .msr_mask = 0x00000000020EFF30ULL,
},
#endif
#if defined (TODO)
@@ -1262,162 +2905,353 @@
{
.name = "Npe405L",
.pvr = CPU_PPC_NPE405L,
- .pvr_mask = 0xFFFF0000,
+ .pvr_mask = 0xFFFFFFFF,
.insns_flags = PPC_INSNS_405,
.flags = PPC_FLAGS_405,
- .msr_mask = 0x00000000020EFF30,
+ .msr_mask = 0x00000000020EFF30ULL,
},
#endif
#if defined (TODO)
+ /* STB010000 */
+ {
+ .name = "STB01000",
+ .pvr = CPU_PPC_STB01000,
+ .pvr_mask = 0xFFFFFFFF,
+ .insns_flags = PPC_INSNS_405,
+ .flags = PPC_FLAGS_405,
+ .msr_mask = 0x00000000020EFF30ULL,
+ },
+#endif
+#if defined (TODO)
+ /* STB01010 */
+ {
+ .name = "STB01010",
+ .pvr = CPU_PPC_STB01010,
+ .pvr_mask = 0xFFFFFFFF,
+ .insns_flags = PPC_INSNS_405,
+ .flags = PPC_FLAGS_405,
+ .msr_mask = 0x00000000020EFF30ULL,
+ },
+#endif
+#if defined (TODO)
+ /* STB0210 */
+ {
+ .name = "STB0210",
+ .pvr = CPU_PPC_STB0210,
+ .pvr_mask = 0xFFFFFFFF,
+ .insns_flags = PPC_INSNS_405,
+ .flags = PPC_FLAGS_405,
+ .msr_mask = 0x00000000020EFF30ULL,
+ },
+#endif
+#if defined (TODO)
/* STB03xx */
{
.name = "STB03",
.pvr = CPU_PPC_STB03,
- .pvr_mask = 0xFFFF0000,
+ .pvr_mask = 0xFFFFFFFF,
.insns_flags = PPC_INSNS_405,
.flags = PPC_FLAGS_405,
- .msr_mask = 0x00000000020EFF30,
+ .msr_mask = 0x00000000020EFF30ULL,
},
#endif
#if defined (TODO)
- /* STB04xx */
+ /* STB043x */
{
- .name = "STB04",
- .pvr = CPU_PPC_STB04,
- .pvr_mask = 0xFFFF0000,
+ .name = "STB043",
+ .pvr = CPU_PPC_STB043,
+ .pvr_mask = 0xFFFFFFFF,
.insns_flags = PPC_INSNS_405,
.flags = PPC_FLAGS_405,
- .msr_mask = 0x00000000020EFF30,
+ .msr_mask = 0x00000000020EFF30ULL,
},
#endif
#if defined (TODO)
+ /* STB045x */
+ {
+ .name = "STB045",
+ .pvr = CPU_PPC_STB045,
+ .pvr_mask = 0xFFFFFFFF,
+ .insns_flags = PPC_INSNS_405,
+ .flags = PPC_FLAGS_405,
+ .msr_mask = 0x00000000020EFF30ULL,
+ },
+#endif
+#if defined (TODO)
/* STB25xx */
{
.name = "STB25",
.pvr = CPU_PPC_STB25,
- .pvr_mask = 0xFFFF0000,
+ .pvr_mask = 0xFFFFFFFF,
.insns_flags = PPC_INSNS_405,
.flags = PPC_FLAGS_405,
- .msr_mask = 0x00000000020EFF30,
+ .msr_mask = 0x00000000020EFF30ULL,
},
#endif
#if defined (TODO)
- /* PPC 440 EP */
+ /* STB130 */
{
+ .name = "STB130",
+ .pvr = CPU_PPC_STB130,
+ .pvr_mask = 0xFFFFFFFF,
+ .insns_flags = PPC_INSNS_405,
+ .flags = PPC_FLAGS_405,
+ .msr_mask = 0x00000000020EFF30ULL,
+ },
+#endif
+ /* Xilinx PowerPC 405 cores */
+#if defined (TODO)
+ {
+ .name = "x2vp4",
+ .pvr = CPU_PPC_X2VP4,
+ .pvr_mask = 0xFFFFFFFF,
+ .insns_flags = PPC_INSNS_405,
+ .flags = PPC_FLAGS_405,
+ .msr_mask = 0x00000000020EFF30ULL,
+ },
+ {
+ .name = "x2vp7",
+ .pvr = CPU_PPC_X2VP7,
+ .pvr_mask = 0xFFFFFFFF,
+ .insns_flags = PPC_INSNS_405,
+ .flags = PPC_FLAGS_405,
+ .msr_mask = 0x00000000020EFF30ULL,
+ },
+ {
+ .name = "x2vp20",
+ .pvr = CPU_PPC_X2VP20,
+ .pvr_mask = 0xFFFFFFFF,
+ .insns_flags = PPC_INSNS_405,
+ .flags = PPC_FLAGS_405,
+ .msr_mask = 0x00000000020EFF30ULL,
+ },
+ {
+ .name = "x2vp50",
+ .pvr = CPU_PPC_X2VP50,
+ .pvr_mask = 0xFFFFFFFF,
+ .insns_flags = PPC_INSNS_405,
+ .flags = PPC_FLAGS_405,
+ .msr_mask = 0x00000000020EFF30ULL,
+ },
+#endif
+#if defined (TODO)
+ /* PowerPC 440 EP */
+ {
.name = "440ep",
.pvr = CPU_PPC_440EP,
.pvr_mask = 0xFFFF0000,
.insns_flags = PPC_INSNS_440,
.flags = PPC_FLAGS_440,
- .msr_mask = 0x000000000006D630,
+ .msr_mask = 0x000000000006D630ULL,
},
#endif
#if defined (TODO)
- /* PPC 440 GP */
+ /* PowerPC 440 GR */
{
+ .name = "440gr",
+ .pvr = CPU_PPC_440GR,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_440,
+ .flags = PPC_FLAGS_440,
+ .msr_mask = 0x000000000006D630ULL,
+ },
+#endif
+#if defined (TODO)
+ /* PowerPC 440 GP */
+ {
.name = "440gp",
.pvr = CPU_PPC_440GP,
.pvr_mask = 0xFFFFFF00,
.insns_flags = PPC_INSNS_440,
.flags = PPC_FLAGS_440,
- .msr_mask = 0x000000000006D630,
+ .msr_mask = 0x000000000006D630ULL,
},
#endif
#if defined (TODO)
- /* PPC 440 GX */
+ /* PowerPC 440 GX */
{
.name = "440gx",
.pvr = CPU_PPC_440GX,
.pvr_mask = 0xFFFF0000,
.insns_flags = PPC_INSNS_405,
.flags = PPC_FLAGS_440,
- .msr_mask = 0x000000000006D630,
+ .msr_mask = 0x000000000006D630ULL,
},
#endif
+#if defined (TODO)
+ /* PowerPC 440 GXc */
+ {
+ .name = "440gxc",
+ .pvr = CPU_PPC_440GXC,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_405,
+ .flags = PPC_FLAGS_440,
+ .msr_mask = 0x000000000006D630ULL,
+ },
+#endif
+#if defined (TODO)
+ /* PowerPC 440 GXf */
+ {
+ .name = "440gxf",
+ .pvr = CPU_PPC_440GXF,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_405,
+ .flags = PPC_FLAGS_440,
+ .msr_mask = 0x000000000006D630ULL,
+ },
+#endif
+#if defined (TODO)
+ /* PowerPC 440 SP */
+ {
+ .name = "440sp",
+ .pvr = CPU_PPC_440SP,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_405,
+ .flags = PPC_FLAGS_440,
+ .msr_mask = 0x000000000006D630ULL,
+ },
+#endif
+#if defined (TODO)
+ /* PowerPC 440 SP2 */
+ {
+ .name = "440sp2",
+ .pvr = CPU_PPC_440SP2,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_405,
+ .flags = PPC_FLAGS_440,
+ .msr_mask = 0x000000000006D630ULL,
+ },
+#endif
+#if defined (TODO)
+ /* PowerPC 440 SPE */
+ {
+ .name = "440spe",
+ .pvr = CPU_PPC_440SPE,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_405,
+ .flags = PPC_FLAGS_440,
+ .msr_mask = 0x000000000006D630ULL,
+ },
+#endif
+ /* Fake generic BookE PowerPC */
+ {
+ .name = "BookE",
+ .pvr = CPU_PPC_e500,
+ .pvr_mask = 0xFFFFFFFF,
+ .insns_flags = PPC_INSNS_BOOKE,
+ .flags = PPC_FLAGS_BOOKE,
+ .msr_mask = 0x000000000006D630ULL,
+ },
+ /* PowerPC 460 cores - TODO */
+ /* PowerPC MPC 5xx cores - TODO */
+ /* PowerPC MPC 8xx cores - TODO */
+ /* PowerPC MPC 8xxx cores - TODO */
+ /* e200 cores - TODO */
+ /* e500 cores - TODO */
+ /* e600 cores - TODO */
- /* 32 bits "classic" powerpc */
+ /* 32 bits "classic" PowerPC */
#if defined (TODO)
- /* PPC 601 */
+ /* PowerPC 601 */
{
.name = "601",
.pvr = CPU_PPC_601,
.pvr_mask = 0xFFFF0000,
.insns_flags = PPC_INSNS_601,
.flags = PPC_FLAGS_601,
- .msr_mask = 0x000000000000FD70,
+ .msr_mask = 0x000000000000FD70ULL,
},
#endif
#if defined (TODO)
- /* PPC 602 */
+ /* PowerPC 602 */
{
.name = "602",
.pvr = CPU_PPC_602,
.pvr_mask = 0xFFFF0000,
.insns_flags = PPC_INSNS_602,
.flags = PPC_FLAGS_602,
- .msr_mask = 0x0000000000C7FF73,
+ .msr_mask = 0x0000000000C7FF73ULL,
},
#endif
-#if defined (TODO)
- /* PPC 603 */
+ /* PowerPC 603 */
{
.name = "603",
.pvr = CPU_PPC_603,
- .pvr_mask = 0xFFFF0000,
+ .pvr_mask = 0xFFFFFFFF,
.insns_flags = PPC_INSNS_603,
.flags = PPC_FLAGS_603,
- .msr_mask = 0x000000000007FF73,
+ .msr_mask = 0x000000000007FF73ULL,
},
-#endif
-#if defined (TODO)
- /* PPC 603e */
+ /* PowerPC 603e */
{
.name = "603e",
.pvr = CPU_PPC_603E,
- .pvr_mask = 0xFFFF0000,
+ .pvr_mask = 0xFFFFFFFF,
.insns_flags = PPC_INSNS_603,
.flags = PPC_FLAGS_603,
- .msr_mask = 0x000000000007FF73,
+ .msr_mask = 0x000000000007FF73ULL,
},
{
.name = "Stretch",
.pvr = CPU_PPC_603E,
- .pvr_mask = 0xFFFF0000,
+ .pvr_mask = 0xFFFFFFFF,
.insns_flags = PPC_INSNS_603,
.flags = PPC_FLAGS_603,
- .msr_mask = 0x000000000007FF73,
+ .msr_mask = 0x000000000007FF73ULL,
},
-#endif
-#if defined (TODO)
- /* PPC 603ev */
+ /* PowerPC 603p */
{
- .name = "603ev",
- .pvr = CPU_PPC_603EV,
- .pvr_mask = 0xFFFFF000,
+ .name = "603p",
+ .pvr = CPU_PPC_603P,
+ .pvr_mask = 0xFFFFFFFF,
.insns_flags = PPC_INSNS_603,
.flags = PPC_FLAGS_603,
- .msr_mask = 0x000000000007FF73,
+ .msr_mask = 0x000000000007FF73ULL,
},
-#endif
-#if defined (TODO)
- /* PPC 603r */
+ /* PowerPC 603e7 */
{
+ .name = "603e7",
+ .pvr = CPU_PPC_603E7,
+ .pvr_mask = 0xFFFFFFFF,
+ .insns_flags = PPC_INSNS_603,
+ .flags = PPC_FLAGS_603,
+ .msr_mask = 0x000000000007FF73ULL,
+ },
+ /* PowerPC 603e7v */
+ {
+ .name = "603e7v",
+ .pvr = CPU_PPC_603E7v,
+ .pvr_mask = 0xFFFFFFFF,
+ .insns_flags = PPC_INSNS_603,
+ .flags = PPC_FLAGS_603,
+ .msr_mask = 0x000000000007FF73ULL,
+ },
+ /* PowerPC 603e7v2 */
+ {
+ .name = "603e7v2",
+ .pvr = CPU_PPC_603E7v2,
+ .pvr_mask = 0xFFFFFFFF,
+ .insns_flags = PPC_INSNS_603,
+ .flags = PPC_FLAGS_603,
+ .msr_mask = 0x000000000007FF73ULL,
+ },
+ /* PowerPC 603r */
+ {
.name = "603r",
.pvr = CPU_PPC_603R,
- .pvr_mask = 0xFFFFF000,
+ .pvr_mask = 0xFFFFFFFF,
.insns_flags = PPC_INSNS_603,
.flags = PPC_FLAGS_603,
- .msr_mask = 0x000000000007FF73,
+ .msr_mask = 0x000000000007FF73ULL,
},
{
.name = "Goldeneye",
.pvr = CPU_PPC_603R,
- .pvr_mask = 0xFFFFF000,
+ .pvr_mask = 0xFFFFFFFF,
.insns_flags = PPC_INSNS_603,
.flags = PPC_FLAGS_603,
- .msr_mask = 0x000000000007FF73,
+ .msr_mask = 0x000000000007FF73ULL,
},
-#endif
#if defined (TODO)
/* XXX: TODO: according to Motorola UM, this is a derivative to 603e */
{
@@ -1426,72 +3260,110 @@
.pvr_mask = 0xFFFF0000,
.insns_flags = PPC_INSNS_G2,
.flags = PPC_FLAGS_G2,
- .msr_mask = 0x000000000006FFF2,
+ .msr_mask = 0x000000000006FFF2ULL,
},
+ {
+ .name = "G2h4",
+ .pvr = CPU_PPC_G2H4,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_G2,
+ .flags = PPC_FLAGS_G2,
+ .msr_mask = 0x000000000006FFF2ULL,
+ },
+ {
+ .name = "G2gp",
+ .pvr = CPU_PPC_G2gp,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_G2,
+ .flags = PPC_FLAGS_G2,
+ .msr_mask = 0x000000000006FFF2ULL,
+ },
+ {
+ .name = "G2ls",
+ .pvr = CPU_PPC_G2ls,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_G2,
+ .flags = PPC_FLAGS_G2,
+ .msr_mask = 0x000000000006FFF2ULL,
+ },
{ /* Same as G2, with LE mode support */
.name = "G2le",
.pvr = CPU_PPC_G2LE,
.pvr_mask = 0xFFFF0000,
.insns_flags = PPC_INSNS_G2,
.flags = PPC_FLAGS_G2,
- .msr_mask = 0x000000000007FFF3,
+ .msr_mask = 0x000000000007FFF3ULL,
},
+ {
+ .name = "G2legp",
+ .pvr = CPU_PPC_G2LEgp,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_G2,
+ .flags = PPC_FLAGS_G2,
+ .msr_mask = 0x000000000007FFF3ULL,
+ },
+ {
+ .name = "G2lels",
+ .pvr = CPU_PPC_G2LEls,
+ .pvr_mask = 0xFFFF0000,
+ .insns_flags = PPC_INSNS_G2,
+ .flags = PPC_FLAGS_G2,
+ .msr_mask = 0x000000000007FFF3ULL,
+ },
#endif
- /* PPC 604 */
+ /* PowerPC 604 */
{
.name = "604",
.pvr = CPU_PPC_604,
- .pvr_mask = 0xFFFF0000,
+ .pvr_mask = 0xFFFFFFFF,
.insns_flags = PPC_INSNS_604,
.flags = PPC_FLAGS_604,
- .msr_mask = 0x000000000005FF77,
+ .msr_mask = 0x000000000005FF77ULL,
},
- /* PPC 604e */
+ /* PowerPC 604e */
{
.name = "604e",
.pvr = CPU_PPC_604E,
- .pvr_mask = 0xFFFF0000,
+ .pvr_mask = 0xFFFFFFFF,
.insns_flags = PPC_INSNS_604,
.flags = PPC_FLAGS_604,
- .msr_mask = 0x000000000005FF77,
+ .msr_mask = 0x000000000005FF77ULL,
},
- /* PPC 604r */
+ /* PowerPC 604r */
{
.name = "604r",
.pvr = CPU_PPC_604R,
- .pvr_mask = 0xFFFF0000,
+ .pvr_mask = 0xFFFFFFFF,
.insns_flags = PPC_INSNS_604,
.flags = PPC_FLAGS_604,
- .msr_mask = 0x000000000005FF77,
+ .msr_mask = 0x000000000005FF77ULL,
},
/* generic G3 */
{
.name = "G3",
.pvr = CPU_PPC_74x,
- .pvr_mask = 0xFFFFF000,
+ .pvr_mask = 0xFFFFFFFF,
.insns_flags = PPC_INSNS_7x0,
.flags = PPC_FLAGS_7x0,
- .msr_mask = 0x000000000007FF77,
+ .msr_mask = 0x000000000007FF77ULL,
},
-#if defined (TODO)
/* MPC740 (G3) */
{
.name = "740",
.pvr = CPU_PPC_74x,
- .pvr_mask = 0xFFFFF000,
+ .pvr_mask = 0xFFFFFFFF,
.insns_flags = PPC_INSNS_7x0,
.flags = PPC_FLAGS_7x0,
- .msr_mask = 0x000000000007FF77,
+ .msr_mask = 0x000000000007FF77ULL,
},
{
.name = "Arthur",
.pvr = CPU_PPC_74x,
- .pvr_mask = 0xFFFFF000,
+ .pvr_mask = 0xFFFFFFFF,
.insns_flags = PPC_INSNS_7x0,
.flags = PPC_FLAGS_7x0,
- .msr_mask = 0x000000000007FF77,
+ .msr_mask = 0x000000000007FF77ULL,
},
-#endif
#if defined (TODO)
/* MPC745 (G3) */
{
@@ -1500,7 +3372,7 @@
.pvr_mask = 0xFFFFF000,
.insns_flags = PPC_INSNS_7x5,
.flags = PPC_FLAGS_7x5,
- .msr_mask = 0x000000000007FF77,
+ .msr_mask = 0x000000000007FF77ULL,
},
{
.name = "Goldfinger",
@@ -1508,17 +3380,17 @@
.pvr_mask = 0xFFFFF000,
.insns_flags = PPC_INSNS_7x5,
.flags = PPC_FLAGS_7x5,
- .msr_mask = 0x000000000007FF77,
+ .msr_mask = 0x000000000007FF77ULL,
},
#endif
/* MPC750 (G3) */
{
.name = "750",
.pvr = CPU_PPC_74x,
- .pvr_mask = 0xFFFFF000,
+ .pvr_mask = 0xFFFFFFFF,
.insns_flags = PPC_INSNS_7x0,
.flags = PPC_FLAGS_7x0,
- .msr_mask = 0x000000000007FF77,
+ .msr_mask = 0x000000000007FF77ULL,
},
#if defined (TODO)
/* MPC755 (G3) */
@@ -1528,28 +3400,26 @@
.pvr_mask = 0xFFFFF000,
.insns_flags = PPC_INSNS_7x5,
.flags = PPC_FLAGS_7x5,
- .msr_mask = 0x000000000007FF77,
+ .msr_mask = 0x000000000007FF77ULL,
},
#endif
-#if defined (TODO)
/* MPC740P (G3) */
{
.name = "740p",
.pvr = CPU_PPC_74xP,
- .pvr_mask = 0xFFFFF000,
+ .pvr_mask = 0xFFFFFFFF,
.insns_flags = PPC_INSNS_7x0,
.flags = PPC_FLAGS_7x0,
- .msr_mask = 0x000000000007FF77,
+ .msr_mask = 0x000000000007FF77ULL,
},
{
.name = "Conan/Doyle",
.pvr = CPU_PPC_74xP,
- .pvr_mask = 0xFFFFF000,
+ .pvr_mask = 0xFFFFFFFF,
.insns_flags = PPC_INSNS_7x0,
.flags = PPC_FLAGS_7x0,
- .msr_mask = 0x000000000007FF77,
+ .msr_mask = 0x000000000007FF77ULL,
},
-#endif
#if defined (TODO)
/* MPC745P (G3) */
{
@@ -1558,17 +3428,17 @@
.pvr_mask = 0xFFFFF000,
.insns_flags = PPC_INSNS_7x5,
.flags = PPC_FLAGS_7x5,
- .msr_mask = 0x000000000007FF77,
+ .msr_mask = 0x000000000007FF77ULL,
},
#endif
/* MPC750P (G3) */
{
.name = "750p",
.pvr = CPU_PPC_74xP,
- .pvr_mask = 0xFFFFF000,
+ .pvr_mask = 0xFFFFFFFF,
.insns_flags = PPC_INSNS_7x0,
.flags = PPC_FLAGS_7x0,
- .msr_mask = 0x000000000007FF77,
+ .msr_mask = 0x000000000007FF77ULL,
},
#if defined (TODO)
/* MPC755P (G3) */
@@ -1578,35 +3448,35 @@
.pvr_mask = 0xFFFFF000,
.insns_flags = PPC_INSNS_7x5,
.flags = PPC_FLAGS_7x5,
- .msr_mask = 0x000000000007FF77,
+ .msr_mask = 0x000000000007FF77ULL,
},
#endif
/* IBM 750CXe (G3 embedded) */
{
.name = "750cxe",
.pvr = CPU_PPC_750CXE,
- .pvr_mask = 0xFFFFF000,
+ .pvr_mask = 0xFFFFFFFF,
.insns_flags = PPC_INSNS_7x0,
.flags = PPC_FLAGS_7x0,
- .msr_mask = 0x000000000007FF77,
+ .msr_mask = 0x000000000007FF77ULL,
},
/* IBM 750FX (G3 embedded) */
{
.name = "750fx",
.pvr = CPU_PPC_750FX,
- .pvr_mask = 0xFFFF0000,
+ .pvr_mask = 0xFFFFFFFF,
.insns_flags = PPC_INSNS_7x0,
.flags = PPC_FLAGS_7x0,
- .msr_mask = 0x000000000007FF77,
+ .msr_mask = 0x000000000007FF77ULL,
},
/* IBM 750GX (G3 embedded) */
{
.name = "750gx",
.pvr = CPU_PPC_750GX,
- .pvr_mask = 0xFFFF0000,
+ .pvr_mask = 0xFFFFFFFF,
.insns_flags = PPC_INSNS_7x0,
.flags = PPC_FLAGS_7x0,
- .msr_mask = 0x000000000007FF77,
+ .msr_mask = 0x000000000007FF77ULL,
},
#if defined (TODO)
/* generic G4 */
@@ -1616,18 +3486,18 @@
.pvr_mask = 0xFFFF0000,
.insns_flags = PPC_INSNS_74xx,
.flags = PPC_FLAGS_74xx,
- .msr_mask = 0x000000000205FF77,
+ .msr_mask = 0x000000000205FF77ULL,
},
#endif
#if defined (TODO)
- /* PPC 7400 (G4) */
+ /* PowerPC 7400 (G4) */
{
.name = "7400",
.pvr = CPU_PPC_7400,
.pvr_mask = 0xFFFF0000,
.insns_flags = PPC_INSNS_74xx,
.flags = PPC_FLAGS_74xx,
- .msr_mask = 0x000000000205FF77,
+ .msr_mask = 0x000000000205FF77ULL,
},
{
.name = "Max",
@@ -1635,18 +3505,18 @@
.pvr_mask = 0xFFFF0000,
.insns_flags = PPC_INSNS_74xx,
.flags = PPC_FLAGS_74xx,
- .msr_mask = 0x000000000205FF77,
+ .msr_mask = 0x000000000205FF77ULL,
},
#endif
#if defined (TODO)
- /* PPC 7410 (G4) */
+ /* PowerPC 7410 (G4) */
{
.name = "7410",
.pvr = CPU_PPC_7410,
.pvr_mask = 0xFFFF0000,
.insns_flags = PPC_INSNS_74xx,
.flags = PPC_FLAGS_74xx,
- .msr_mask = 0x000000000205FF77,
+ .msr_mask = 0x000000000205FF77ULL,
},
{
.name = "Nitro",
@@ -1654,7 +3524,7 @@
.pvr_mask = 0xFFFF0000,
.insns_flags = PPC_INSNS_74xx,
.flags = PPC_FLAGS_74xx,
- .msr_mask = 0x000000000205FF77,
+ .msr_mask = 0x000000000205FF77ULL,
},
#endif
/* XXX: 7441 */
@@ -1662,14 +3532,14 @@
/* XXX: 7447 */
/* XXX: 7447A */
#if defined (TODO)
- /* PPC 7450 (G4) */
+ /* PowerPC 7450 (G4) */
{
.name = "7450",
.pvr = CPU_PPC_7450,
.pvr_mask = 0xFFFF0000,
.insns_flags = PPC_INSNS_74xx,
.flags = PPC_FLAGS_74xx,
- .msr_mask = 0x000000000205FF77,
+ .msr_mask = 0x000000000205FF77ULL,
},
{
.name = "Vger",
@@ -1677,19 +3547,19 @@
.pvr_mask = 0xFFFF0000,
.insns_flags = PPC_INSNS_74xx,
.flags = PPC_FLAGS_74xx,
- .msr_mask = 0x000000000205FF77,
+ .msr_mask = 0x000000000205FF77ULL,
},
#endif
/* XXX: 7451 */
#if defined (TODO)
- /* PPC 7455 (G4) */
+ /* PowerPC 7455 (G4) */
{
.name = "7455",
.pvr = CPU_PPC_7455,
.pvr_mask = 0xFFFF0000,
.insns_flags = PPC_INSNS_74xx,
.flags = PPC_FLAGS_74xx,
- .msr_mask = 0x000000000205FF77,
+ .msr_mask = 0x000000000205FF77ULL,
},
{
.name = "Apollo 6",
@@ -1697,18 +3567,18 @@
.pvr_mask = 0xFFFF0000,
.insns_flags = PPC_INSNS_74xx,
.flags = PPC_FLAGS_74xx,
- .msr_mask = 0x000000000205FF77,
+ .msr_mask = 0x000000000205FF77ULL,
},
#endif
#if defined (TODO)
- /* PPC 7457 (G4) */
+ /* PowerPC 7457 (G4) */
{
.name = "7457",
.pvr = CPU_PPC_7457,
.pvr_mask = 0xFFFF0000,
.insns_flags = PPC_INSNS_74xx,
.flags = PPC_FLAGS_74xx,
- .msr_mask = 0x000000000205FF77,
+ .msr_mask = 0x000000000205FF77ULL,
},
{
.name = "Apollo 7",
@@ -1716,18 +3586,18 @@
.pvr_mask = 0xFFFF0000,
.insns_flags = PPC_INSNS_74xx,
.flags = PPC_FLAGS_74xx,
- .msr_mask = 0x000000000205FF77,
+ .msr_mask = 0x000000000205FF77ULL,
},
#endif
#if defined (TODO)
- /* PPC 7457A (G4) */
+ /* PowerPC 7457A (G4) */
{
.name = "7457A",
.pvr = CPU_PPC_7457A,
.pvr_mask = 0xFFFF0000,
.insns_flags = PPC_INSNS_74xx,
.flags = PPC_FLAGS_74xx,
- .msr_mask = 0x000000000205FF77,
+ .msr_mask = 0x000000000205FF77ULL,
},
{
.name = "Apollo 7 PM",
@@ -1735,23 +3605,24 @@
.pvr_mask = 0xFFFF0000,
.insns_flags = PPC_INSNS_74xx,
.flags = PPC_FLAGS_74xx,
- .msr_mask = 0x000000000205FF77,
+ .msr_mask = 0x000000000205FF77ULL,
},
#endif
- /* 64 bits PPC */
+ /* 64 bits PowerPC */
+#if defined (TARGET_PPC64)
#if defined (TODO)
- /* PPC 620 */
+ /* PowerPC 620 */
{
.name = "620",
.pvr = CPU_PPC_620,
.pvr_mask = 0xFFFF0000,
.insns_flags = PPC_INSNS_620,
.flags = PPC_FLAGS_620,
- .msr_mask = 0x800000000005FF73,
+ .msr_mask = 0x800000000005FF73ULL,
},
#endif
#if defined (TODO)
- /* PPC 630 (POWER3) */
+ /* PowerPC 630 (POWER3) */
{
.name = "630",
.pvr = CPU_PPC_630,
@@ -1770,7 +3641,7 @@
}
#endif
#if defined (TODO)
- /* PPC 631 (Power 3+)*/
+ /* PowerPC 631 (Power 3+)*/
{
.name = "631",
.pvr = CPU_PPC_631,
@@ -1833,25 +3704,25 @@
},
#endif
#if defined (TODO)
- /* PPC 970 */
+ /* PowerPC 970 */
{
.name = "970",
.pvr = CPU_PPC_970,
.pvr_mask = 0xFFFF0000,
.insns_flags = PPC_INSNS_970,
.flags = PPC_FLAGS_970,
- .msr_mask = 0x900000000204FF36,
+ .msr_mask = 0x900000000204FF36ULL,
},
#endif
#if defined (TODO)
- /* PPC 970FX (G5) */
+ /* PowerPC 970FX (G5) */
{
.name = "970fx",
.pvr = CPU_PPC_970FX,
.pvr_mask = 0xFFFF0000,
.insns_flags = PPC_INSNS_970FX,
.flags = PPC_FLAGS_970FX,
- .msr_mask = 0x800000000204FF36,
+ .msr_mask = 0x800000000204FF36ULL,
},
#endif
#if defined (TODO)
@@ -1977,6 +3848,7 @@
.msr_mask = xxx,
},
#endif
+#endif /* defined (TARGET_PPC64) */
#if defined (TODO)
/* POWER2 */
{
@@ -1996,25 +3868,25 @@
.pvr_mask = 0xFFFF0000,
.insns_flags = PPC_INSNS_PPC64,
.flags = PPC_FLAGS_PPC64,
- .msr_mask = 0xA00000000204FF36,
+ .msr_mask = 0xA00000000204FF36ULL,
},
#endif
{
.name = "ppc32",
.pvr = CPU_PPC_604,
- .pvr_mask = 0xFFFF0000,
+ .pvr_mask = 0xFFFFFFFF,
.insns_flags = PPC_INSNS_PPC32,
.flags = PPC_FLAGS_PPC32,
- .msr_mask = 0x000000000005FF77,
+ .msr_mask = 0x000000000005FF77ULL,
},
/* Fallback */
{
.name = "ppc",
.pvr = CPU_PPC_604,
- .pvr_mask = 0xFFFF0000,
+ .pvr_mask = 0xFFFFFFFF,
.insns_flags = PPC_INSNS_PPC32,
.flags = PPC_FLAGS_PPC32,
- .msr_mask = 0x000000000005FF77,
+ .msr_mask = 0x000000000005FF77ULL,
},
};
@@ -2058,7 +3930,7 @@
int i;
for (i = 0; ; i++) {
- (*cpu_fprintf)(f, "PowerPC '%s' PVR %08x mask %08x\n",
+ (*cpu_fprintf)(f, "PowerPC %16s PVR %08x mask %08x\n",
ppc_defs[i].name,
ppc_defs[i].pvr, ppc_defs[i].pvr_mask);
if (strcmp(ppc_defs[i].name, "ppc") == 0)
Modified: trunk/src/host/qemu-neo1973/target-sh4/cpu.h
===================================================================
--- trunk/src/host/qemu-neo1973/target-sh4/cpu.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/target-sh4/cpu.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -121,9 +121,8 @@
CPUSH4State *cpu_sh4_init(void);
int cpu_sh4_exec(CPUSH4State * s);
-struct siginfo;
-int cpu_sh4_signal_handler(int hostsignum, struct siginfo *info,
- void *puc);
+int cpu_sh4_signal_handler(int host_signum, void *pinfo,
+ void *puc);
#include "softfloat.h"
Modified: trunk/src/host/qemu-neo1973/target-sh4/helper.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-sh4/helper.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/target-sh4/helper.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -53,7 +53,7 @@
return 1;
}
-target_ulong cpu_get_phys_page_debug(CPUState * env, target_ulong addr)
+target_phys_addr_t cpu_get_phys_page_debug(CPUState * env, target_ulong addr)
{
return addr;
}
@@ -429,7 +429,7 @@
return tlb_set_page(env, address, physical, prot, is_user, is_softmmu);
}
-target_ulong cpu_get_phys_page_debug(CPUState * env, target_ulong addr)
+target_phys_addr_t cpu_get_phys_page_debug(CPUState * env, target_ulong addr)
{
target_ulong physical;
int prot;
Modified: trunk/src/host/qemu-neo1973/target-sh4/op.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-sh4/op.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/target-sh4/op.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -737,7 +737,7 @@
void OPPROTO op_dec8_rN(void)
{
- env->gregs[PARAM1] -= 4;
+ env->gregs[PARAM1] -= 8;
RETURN();
}
@@ -761,7 +761,7 @@
void OPPROTO op_inc8_rN(void)
{
- env->gregs[PARAM1] += 4;
+ env->gregs[PARAM1] += 8;
RETURN();
}
Modified: trunk/src/host/qemu-neo1973/target-sh4/translate.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-sh4/translate.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/target-sh4/translate.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -1003,8 +1003,8 @@
LDST(mach, 0x400a, 0x4006, lds, 0x000a, 0x4002, sts,)
LDST(macl, 0x401a, 0x4016, lds, 0x001a, 0x4012, sts,)
LDST(pr, 0x402a, 0x4026, lds, 0x002a, 0x4022, sts,)
- LDST(fpul, 0x405a, 0x4056, lds, 0x005a, 0x0052, sts,)
- LDST(fpscr, 0x406a, 0x4066, lds, 0x006a, 0x0062, sts, ctx->flags |=
+ LDST(fpul, 0x405a, 0x4056, lds, 0x005a, 0x4052, sts,)
+ LDST(fpscr, 0x406a, 0x4066, lds, 0x006a, 0x4062, sts, ctx->flags |=
MODE_CHANGE;)
case 0x00c3: /* movca.l R0, at Rm */
gen_op_movl_rN_T0(REG(0));
@@ -1087,8 +1087,9 @@
ctx->flags |= BRANCH_EXCEPTION;
}
-int gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb,
- int search_pc)
+static inline int
+gen_intermediate_code_internal(CPUState * env, TranslationBlock * tb,
+ int search_pc)
{
DisasContext ctx;
target_ulong pc_start;
Modified: trunk/src/host/qemu-neo1973/target-sparc/cpu.h
===================================================================
--- trunk/src/host/qemu-neo1973/target-sparc/cpu.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/target-sparc/cpu.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -35,10 +35,14 @@
#define TT_NFPU_INSN 0x04
#define TT_WIN_OVF 0x05
#define TT_WIN_UNF 0x06
+#define TT_UNALIGNED 0x07
#define TT_FP_EXCP 0x08
#define TT_DFAULT 0x09
+#define TT_TOVF 0x0a
#define TT_EXTINT 0x10
+#define TT_DATA_ACCESS 0x29
#define TT_DIV_ZERO 0x2a
+#define TT_NCP_INSN 0x24
#define TT_TRAP 0x80
#else
#define TT_TFAULT 0x08
@@ -47,11 +51,14 @@
#define TT_PRIV_INSN 0x11
#define TT_NFPU_INSN 0x20
#define TT_FP_EXCP 0x21
+#define TT_TOVF 0x23
#define TT_CLRWIN 0x24
#define TT_DIV_ZERO 0x28
#define TT_DFAULT 0x30
#define TT_DMISS 0x31
-#define TT_DPROT 0x32
+#define TT_DATA_ACCESS 0x32
+#define TT_DPROT 0x33
+#define TT_UNALIGNED 0x34
#define TT_PRIV_ACT 0x37
#define TT_EXTINT 0x40
#define TT_SPILL 0x80
@@ -124,6 +131,7 @@
#define FSR_FTT_MASK (FSR_FTT2 | FSR_FTT1 | FSR_FTT0)
#define FSR_FTT_IEEE_EXCP (1 << 14)
#define FSR_FTT_UNIMPFPOP (3 << 14)
+#define FSR_FTT_SEQ_ERROR (4 << 14)
#define FSR_FTT_INVAL_FPR (6 << 14)
#define FSR_FCC1 (1<<11)
@@ -150,6 +158,8 @@
/* 2 <= NWINDOWS <= 32. In QEMU it must also be a power of two. */
#define NWINDOWS 8
+typedef struct sparc_def_t sparc_def_t;
+
typedef struct CPUSPARCState {
target_ulong gregs[8]; /* general registers */
target_ulong *regwptr; /* pointer to current register window */
@@ -168,6 +178,7 @@
int psret; /* enable traps */
uint32_t psrpil; /* interrupt level */
int psref; /* enable fpu */
+ target_ulong version;
jmp_buf jmp_env;
int user_mode_only;
int exception_index;
@@ -213,10 +224,12 @@
uint64_t bgregs[8]; /* backup for normal global registers */
uint64_t igregs[8]; /* interrupt general registers */
uint64_t mgregs[8]; /* mmu general registers */
- uint64_t version;
uint64_t fprs;
uint64_t tick_cmpr, stick_cmpr;
uint64_t gsr;
+ uint32_t gl; // UA2005
+ /* UA 2005 hyperprivileged registers */
+ uint64_t hpstate, htstate[MAXTL], hintp, htba, hver, hstick_cmpr, ssr;
#endif
#if !defined(TARGET_SPARC64) && !defined(reg_T2)
target_ulong t2;
@@ -231,22 +244,22 @@
#define PUT_FSR64(env, val) do { uint64_t _tmp = val; \
env->fsr = _tmp & 0x3fcfc1c3ffULL; \
} while (0)
-// Manuf 0x17, version 0x11, mask 0 (UltraSparc-II)
-#define GET_VER(env) ((0x17ULL << 48) | (0x11ULL << 32) | \
- (0 << 24) | (MAXTL << 8) | (NWINDOWS - 1))
#else
#define GET_FSR32(env) (env->fsr)
-#define PUT_FSR32(env, val) do { uint32_t _tmp = val; \
- env->fsr = _tmp & 0xcfc1ffff; \
+#define PUT_FSR32(env, val) do { uint32_t _tmp = val; \
+ env->fsr = (_tmp & 0xcfc1dfff) | (env->fsr & 0x000e0000); \
} while (0)
#endif
CPUSPARCState *cpu_sparc_init(void);
int cpu_sparc_exec(CPUSPARCState *s);
int cpu_sparc_close(CPUSPARCState *s);
+int sparc_find_by_name (const unsigned char *name, const sparc_def_t **def);
+void sparc_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt,
+ ...));
+int cpu_sparc_register (CPUSPARCState *env, const sparc_def_t *def);
-/* Fake impl 0, version 4 */
-#define GET_PSR(env) ((0 << 28) | (4 << 24) | (env->psr & PSR_ICC) | \
+#define GET_PSR(env) (env->version | (env->psr & PSR_ICC) | \
(env->psref? PSR_EF : 0) | \
(env->psrpil << 8) | \
(env->psrs? PSR_S : 0) | \
@@ -264,7 +277,7 @@
env->psrs = (_tmp & PSR_S)? 1 : 0; \
env->psrps = (_tmp & PSR_PS)? 1 : 0; \
env->psret = (_tmp & PSR_ET)? 1 : 0; \
- cpu_set_cwp(env, _tmp & PSR_CWP & (NWINDOWS - 1)); \
+ cpu_set_cwp(env, _tmp & PSR_CWP); \
} while (0)
#ifdef TARGET_SPARC64
@@ -275,8 +288,8 @@
} while (0)
#endif
-struct siginfo;
-int cpu_sparc_signal_handler(int hostsignum, struct siginfo *info, void *puc);
+int cpu_sparc_signal_handler(int host_signum, void *pinfo, void *puc);
+void raise_exception(int tt);
#include "cpu-all.h"
Modified: trunk/src/host/qemu-neo1973/target-sparc/exec.h
===================================================================
--- trunk/src/host/qemu-neo1973/target-sparc/exec.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/target-sparc/exec.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -1,9 +1,10 @@
#ifndef EXEC_SPARC_H
#define EXEC_SPARC_H 1
+#include "config.h"
#include "dyngen-exec.h"
-#include "config.h"
register struct CPUSPARCState *env asm(AREG0);
+
#ifdef TARGET_SPARC64
#define T0 (env->t0)
#define T1 (env->t1)
@@ -15,7 +16,11 @@
#undef REG_REGWPTR // Broken
#ifdef REG_REGWPTR
+#if defined(__sparc__)
+register uint32_t *REGWPTR asm(AREG4);
+#else
register uint32_t *REGWPTR asm(AREG3);
+#endif
#define reg_REGWPTR
#ifdef AREG4
@@ -28,9 +33,9 @@
#else
#define REGWPTR env->regwptr
register uint32_t T2 asm(AREG3);
+#endif
#define reg_T2
#endif
-#endif
#define FT0 (env->ft0)
#define FT1 (env->ft1)
@@ -56,6 +61,8 @@
void do_fsqrtd(void);
void do_fcmps(void);
void do_fcmpd(void);
+void do_fcmpes(void);
+void do_fcmped(void);
#ifdef TARGET_SPARC64
void do_fabsd(void);
void do_fcmps_fcc1(void);
@@ -64,6 +71,12 @@
void do_fcmpd_fcc2(void);
void do_fcmps_fcc3(void);
void do_fcmpd_fcc3(void);
+void do_fcmpes_fcc1(void);
+void do_fcmped_fcc1(void);
+void do_fcmpes_fcc2(void);
+void do_fcmped_fcc2(void);
+void do_fcmpes_fcc3(void);
+void do_fcmped_fcc3(void);
void do_popc();
void do_wrpstate();
void do_done();
@@ -74,6 +87,7 @@
void do_ldd_raw(target_ulong addr);
void do_interrupt(int intno);
void raise_exception(int tt);
+void check_ieee_exceptions();
void memcpy32(target_ulong *dst, const target_ulong *src);
target_ulong mmu_probe(CPUState *env, target_ulong address, int mmulev);
void dump_mmu(CPUState *env);
Modified: trunk/src/host/qemu-neo1973/target-sparc/op.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-sparc/op.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/target-sparc/op.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -472,6 +472,96 @@
FORCE_RET();
}
+void OPPROTO op_tadd_T1_T0_cc(void)
+{
+ target_ulong src1;
+
+ src1 = T0;
+ T0 += T1;
+ env->psr = 0;
+#ifdef TARGET_SPARC64
+ if (!(T0 & 0xffffffff))
+ env->psr |= PSR_ZERO;
+ if ((int32_t) T0 < 0)
+ env->psr |= PSR_NEG;
+ if ((T0 & 0xffffffff) < (src1 & 0xffffffff))
+ env->psr |= PSR_CARRY;
+ if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff) ^ -1) &
+ ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31))
+ env->psr |= PSR_OVF;
+ if ((src1 & 0x03) || (T1 & 0x03))
+ env->psr |= PSR_OVF;
+
+ env->xcc = 0;
+ if (!T0)
+ env->xcc |= PSR_ZERO;
+ if ((int64_t) T0 < 0)
+ env->xcc |= PSR_NEG;
+ if (T0 < src1)
+ env->xcc |= PSR_CARRY;
+ if (((src1 ^ T1 ^ -1) & (src1 ^ T0)) & (1ULL << 63))
+ env->xcc |= PSR_OVF;
+#else
+ if (!T0)
+ env->psr |= PSR_ZERO;
+ if ((int32_t) T0 < 0)
+ env->psr |= PSR_NEG;
+ if (T0 < src1)
+ env->psr |= PSR_CARRY;
+ if (((src1 ^ T1 ^ -1) & (src1 ^ T0)) & (1 << 31))
+ env->psr |= PSR_OVF;
+ if ((src1 & 0x03) || (T1 & 0x03))
+ env->psr |= PSR_OVF;
+#endif
+ FORCE_RET();
+}
+
+void OPPROTO op_tadd_T1_T0_ccTV(void)
+{
+ target_ulong src1;
+
+ if ((T0 & 0x03) || (T1 & 0x03))
+ raise_exception(TT_TOVF);
+
+ src1 = T0;
+ T0 += T1;
+
+#ifdef TARGET_SPARC64
+ if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff) ^ -1) &
+ ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31))
+ raise_exception(TT_TOVF);
+#else
+ if ((src1 & 0x03) || (T1 & 0x03))
+ raise_exception(TT_TOVF);
+#endif
+
+ env->psr = 0;
+#ifdef TARGET_SPARC64
+ if (!(T0 & 0xffffffff))
+ env->psr |= PSR_ZERO;
+ if ((int32_t) T0 < 0)
+ env->psr |= PSR_NEG;
+ if ((T0 & 0xffffffff) < (src1 & 0xffffffff))
+ env->psr |= PSR_CARRY;
+
+ env->xcc = 0;
+ if (!T0)
+ env->xcc |= PSR_ZERO;
+ if ((int64_t) T0 < 0)
+ env->xcc |= PSR_NEG;
+ if (T0 < src1)
+ env->xcc |= PSR_CARRY;
+#else
+ if (!T0)
+ env->psr |= PSR_ZERO;
+ if ((int32_t) T0 < 0)
+ env->psr |= PSR_NEG;
+ if (T0 < src1)
+ env->psr |= PSR_CARRY;
+#endif
+ FORCE_RET();
+}
+
void OPPROTO op_sub_T1_T0(void)
{
T0 -= T1;
@@ -582,6 +672,96 @@
FORCE_RET();
}
+void OPPROTO op_tsub_T1_T0_cc(void)
+{
+ target_ulong src1;
+
+ src1 = T0;
+ T0 -= T1;
+ env->psr = 0;
+#ifdef TARGET_SPARC64
+ if (!(T0 & 0xffffffff))
+ env->psr |= PSR_ZERO;
+ if ((int32_t) T0 < 0)
+ env->psr |= PSR_NEG;
+ if ((src1 & 0xffffffff) < (T1 & 0xffffffff))
+ env->psr |= PSR_CARRY;
+ if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff)) &
+ ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31))
+ env->psr |= PSR_OVF;
+ if ((src1 & 0x03) || (T1 & 0x03))
+ env->psr |= PSR_OVF;
+
+ env->xcc = 0;
+ if (!T0)
+ env->xcc |= PSR_ZERO;
+ if ((int64_t) T0 < 0)
+ env->xcc |= PSR_NEG;
+ if (src1 < T1)
+ env->xcc |= PSR_CARRY;
+ if (((src1 ^ T1) & (src1 ^ T0)) & (1ULL << 63))
+ env->xcc |= PSR_OVF;
+#else
+ if (!T0)
+ env->psr |= PSR_ZERO;
+ if ((int32_t) T0 < 0)
+ env->psr |= PSR_NEG;
+ if (src1 < T1)
+ env->psr |= PSR_CARRY;
+ if (((src1 ^ T1) & (src1 ^ T0)) & (1 << 31))
+ env->psr |= PSR_OVF;
+ if ((src1 & 0x03) || (T1 & 0x03))
+ env->psr |= PSR_OVF;
+#endif
+ FORCE_RET();
+}
+
+void OPPROTO op_tsub_T1_T0_ccTV(void)
+{
+ target_ulong src1;
+
+ if ((T0 & 0x03) || (T1 & 0x03))
+ raise_exception(TT_TOVF);
+
+ src1 = T0;
+ T0 -= T1;
+
+#ifdef TARGET_SPARC64
+ if ((((src1 & 0xffffffff) ^ (T1 & 0xffffffff)) &
+ ((src1 & 0xffffffff) ^ (T0 & 0xffffffff))) & (1 << 31))
+ raise_exception(TT_TOVF);
+#else
+ if (((src1 ^ T1) & (src1 ^ T0)) & (1 << 31))
+ raise_exception(TT_TOVF);
+#endif
+
+ env->psr = 0;
+#ifdef TARGET_SPARC64
+ if (!(T0 & 0xffffffff))
+ env->psr |= PSR_ZERO;
+ if ((int32_t) T0 < 0)
+ env->psr |= PSR_NEG;
+ if ((src1 & 0xffffffff) < (T1 & 0xffffffff))
+ env->psr |= PSR_CARRY;
+
+ env->xcc = 0;
+ if (!T0)
+ env->xcc |= PSR_ZERO;
+ if ((int64_t) T0 < 0)
+ env->xcc |= PSR_NEG;
+ if (src1 < T1)
+ env->xcc |= PSR_CARRY;
+#else
+ if (!T0)
+ env->psr |= PSR_ZERO;
+ if ((int32_t) T0 < 0)
+ env->psr |= PSR_NEG;
+ if (src1 < T1)
+ env->psr |= PSR_CARRY;
+#endif
+ FORCE_RET();
+}
+
void OPPROTO op_and_T1_T0(void)
{
T0 &= T1;
@@ -671,6 +851,11 @@
x0 = T0 | ((uint64_t) (env->y) << 32);
x1 = T1;
+
+ if (x1 == 0) {
+ raise_exception(TT_DIV_ZERO);
+ }
+
x0 = x0 / x1;
if (x0 > 0xffffffff) {
T0 = 0xffffffff;
@@ -689,6 +874,11 @@
x0 = T0 | ((int64_t) (env->y) << 32);
x1 = T1;
+
+ if (x1 == 0) {
+ raise_exception(TT_DIV_ZERO);
+ }
+
x0 = x0 / x1;
if ((int32_t) x0 != x0) {
T0 = x0 < 0? 0x80000000: 0x7fffffff;
@@ -736,12 +926,18 @@
void OPPROTO op_udivx_T1_T0(void)
{
+ if (T1 == 0) {
+ raise_exception(TT_DIV_ZERO);
+ }
T0 /= T1;
FORCE_RET();
}
void OPPROTO op_sdivx_T1_T0(void)
{
+ if (T1 == 0) {
+ raise_exception(TT_DIV_ZERO);
+ }
if (T0 == INT64_MIN && T1 == -1)
T0 = INT64_MIN;
else
@@ -775,38 +971,43 @@
void OPPROTO op_sll(void)
{
- T0 <<= T1;
+ T0 <<= (T1 & 0x1f);
}
#ifdef TARGET_SPARC64
+void OPPROTO op_sllx(void)
+{
+ T0 <<= (T1 & 0x3f);
+}
+
void OPPROTO op_srl(void)
{
- T0 = (T0 & 0xffffffff) >> T1;
+ T0 = (T0 & 0xffffffff) >> (T1 & 0x1f);
}
void OPPROTO op_srlx(void)
{
- T0 >>= T1;
+ T0 >>= (T1 & 0x3f);
}
void OPPROTO op_sra(void)
{
- T0 = ((int32_t) (T0 & 0xffffffff)) >> T1;
+ T0 = ((int32_t) (T0 & 0xffffffff)) >> (T1 & 0x1f);
}
void OPPROTO op_srax(void)
{
- T0 = ((int64_t) T0) >> T1;
+ T0 = ((int64_t) T0) >> (T1 & 0x3f);
}
#else
void OPPROTO op_srl(void)
{
- T0 >>= T1;
+ T0 >>= (T1 & 0x1f);
}
void OPPROTO op_sra(void)
{
- T0 = ((int32_t) T0) >> T1;
+ T0 = ((int32_t) T0) >> (T1 & 0x1f);
}
#endif
@@ -900,7 +1101,7 @@
void OPPROTO op_wrtick(void)
{
- // XXX write cycle counter and bit 31
+ T0 = 0; // XXX write cycle counter and bit 31
}
void OPPROTO op_rdtpc(void)
@@ -1291,7 +1492,10 @@
void OPPROTO op_movl_npc_T0(void)
{
- env->npc = T0;
+ if (T0 & 0x3)
+ raise_exception(TT_UNALIGNED);
+ else
+ env->npc = T0;
}
void OPPROTO op_mov_pc_npc(void)
@@ -1339,16 +1543,25 @@
helper_flush(T0);
}
+void OPPROTO op_clear_ieee_excp_and_FTT(void)
+{
+ env->fsr &= ~(FSR_FTT_MASK | FSR_CEXC_MASK);;
+}
+
#define F_OP(name, p) void OPPROTO op_f##name##p(void)
#define F_BINOP(name) \
F_OP(name, s) \
{ \
+ set_float_exception_flags(0, &env->fp_status); \
FT0 = float32_ ## name (FT0, FT1, &env->fp_status); \
+ check_ieee_exceptions(); \
} \
F_OP(name, d) \
{ \
+ set_float_exception_flags(0, &env->fp_status); \
DT0 = float64_ ## name (DT0, DT1, &env->fp_status); \
+ check_ieee_exceptions(); \
}
F_BINOP(add);
@@ -1359,9 +1572,11 @@
void OPPROTO op_fsmuld(void)
{
+ set_float_exception_flags(0, &env->fp_status);
DT0 = float64_mul(float32_to_float64(FT0, &env->fp_status),
float32_to_float64(FT1, &env->fp_status),
&env->fp_status);
+ check_ieee_exceptions();
}
#define F_HELPER(name) \
@@ -1387,6 +1602,7 @@
}
F_HELPER(cmp);
+F_HELPER(cmpe);
#ifdef TARGET_SPARC64
F_OP(neg, d)
@@ -1428,6 +1644,37 @@
{
do_fcmpd_fcc3();
}
+
+void OPPROTO op_fcmpes_fcc1(void)
+{
+ do_fcmpes_fcc1();
+}
+
+void OPPROTO op_fcmped_fcc1(void)
+{
+ do_fcmped_fcc1();
+}
+
+void OPPROTO op_fcmpes_fcc2(void)
+{
+ do_fcmpes_fcc2();
+}
+
+void OPPROTO op_fcmped_fcc2(void)
+{
+ do_fcmped_fcc2();
+}
+
+void OPPROTO op_fcmpes_fcc3(void)
+{
+ do_fcmpes_fcc3();
+}
+
+void OPPROTO op_fcmped_fcc3(void)
+{
+ do_fcmped_fcc3();
+}
+
#endif
/* Integer to float conversion. */
@@ -1436,23 +1683,31 @@
#else
F_OP(ito, s)
{
+ set_float_exception_flags(0, &env->fp_status);
FT0 = int32_to_float32(*((int32_t *)&FT1), &env->fp_status);
+ check_ieee_exceptions();
}
F_OP(ito, d)
{
+ set_float_exception_flags(0, &env->fp_status);
DT0 = int32_to_float64(*((int32_t *)&FT1), &env->fp_status);
+ check_ieee_exceptions();
}
#ifdef TARGET_SPARC64
F_OP(xto, s)
{
+ set_float_exception_flags(0, &env->fp_status);
FT0 = int64_to_float32(*((int64_t *)&DT1), &env->fp_status);
+ check_ieee_exceptions();
}
F_OP(xto, d)
{
+ set_float_exception_flags(0, &env->fp_status);
DT0 = int64_to_float64(*((int64_t *)&DT1), &env->fp_status);
+ check_ieee_exceptions();
}
#endif
#endif
@@ -1461,34 +1716,46 @@
/* floating point conversion */
void OPPROTO op_fdtos(void)
{
+ set_float_exception_flags(0, &env->fp_status);
FT0 = float64_to_float32(DT1, &env->fp_status);
+ check_ieee_exceptions();
}
void OPPROTO op_fstod(void)
{
+ set_float_exception_flags(0, &env->fp_status);
DT0 = float32_to_float64(FT1, &env->fp_status);
+ check_ieee_exceptions();
}
/* Float to integer conversion. */
void OPPROTO op_fstoi(void)
{
- *((int32_t *)&FT0) = float32_to_int32(FT1, &env->fp_status);
+ set_float_exception_flags(0, &env->fp_status);
+ *((int32_t *)&FT0) = float32_to_int32_round_to_zero(FT1, &env->fp_status);
+ check_ieee_exceptions();
}
void OPPROTO op_fdtoi(void)
{
- *((int32_t *)&FT0) = float64_to_int32(DT1, &env->fp_status);
+ set_float_exception_flags(0, &env->fp_status);
+ *((int32_t *)&FT0) = float64_to_int32_round_to_zero(DT1, &env->fp_status);
+ check_ieee_exceptions();
}
#ifdef TARGET_SPARC64
void OPPROTO op_fstox(void)
{
- *((int64_t *)&DT0) = float32_to_int64(FT1, &env->fp_status);
+ set_float_exception_flags(0, &env->fp_status);
+ *((int64_t *)&DT0) = float32_to_int64_round_to_zero(FT1, &env->fp_status);
+ check_ieee_exceptions();
}
void OPPROTO op_fdtox(void)
{
- *((int64_t *)&DT0) = float64_to_int64(DT1, &env->fp_status);
+ set_float_exception_flags(0, &env->fp_status);
+ *((int64_t *)&DT0) = float64_to_int64_round_to_zero(DT1, &env->fp_status);
+ check_ieee_exceptions();
}
void OPPROTO op_fmovs_cc(void)
@@ -1557,8 +1824,7 @@
void OPPROTO op_sir(void)
{
- // XXX
-
+ T0 = 0; // XXX
}
void OPPROTO op_ld_asi_reg()
@@ -1585,6 +1851,44 @@
}
#ifdef TARGET_SPARC64
+// This function uses non-native bit order
+#define GET_FIELD(X, FROM, TO) \
+ ((X) >> (63 - (TO)) & ((1ULL << ((TO) - (FROM) + 1)) - 1))
+
+// This function uses the order in the manuals, i.e. bit 0 is 2^0
+#define GET_FIELD_SP(X, FROM, TO) \
+ GET_FIELD(X, 63 - (TO), 63 - (FROM))
+
+void OPPROTO op_array8()
+{
+ T0 = (GET_FIELD_SP(T0, 60, 63) << (17 + 2 * T1)) |
+ (GET_FIELD_SP(T0, 39, 39 + T1 - 1) << (17 + T1)) |
+ (GET_FIELD_SP(T0, 17 + T1 - 1, 17) << 17) |
+ (GET_FIELD_SP(T0, 56, 59) << 13) | (GET_FIELD_SP(T0, 35, 38) << 9) |
+ (GET_FIELD_SP(T0, 13, 16) << 5) | (((T0 >> 55) & 1) << 4) |
+ (GET_FIELD_SP(T0, 33, 34) << 2) | GET_FIELD_SP(T0, 11, 12);
+}
+
+void OPPROTO op_array16()
+{
+ T0 = ((GET_FIELD_SP(T0, 60, 63) << (17 + 2 * T1)) |
+ (GET_FIELD_SP(T0, 39, 39 + T1 - 1) << (17 + T1)) |
+ (GET_FIELD_SP(T0, 17 + T1 - 1, 17) << 17) |
+ (GET_FIELD_SP(T0, 56, 59) << 13) | (GET_FIELD_SP(T0, 35, 38) << 9) |
+ (GET_FIELD_SP(T0, 13, 16) << 5) | (((T0 >> 55) & 1) << 4) |
+ (GET_FIELD_SP(T0, 33, 34) << 2) | GET_FIELD_SP(T0, 11, 12)) << 1;
+}
+
+void OPPROTO op_array32()
+{
+ T0 = ((GET_FIELD_SP(T0, 60, 63) << (17 + 2 * T1)) |
+ (GET_FIELD_SP(T0, 39, 39 + T1 - 1) << (17 + T1)) |
+ (GET_FIELD_SP(T0, 17 + T1 - 1, 17) << 17) |
+ (GET_FIELD_SP(T0, 56, 59) << 13) | (GET_FIELD_SP(T0, 35, 38) << 9) |
+ (GET_FIELD_SP(T0, 13, 16) << 5) | (((T0 >> 55) & 1) << 4) |
+ (GET_FIELD_SP(T0, 33, 34) << 2) | GET_FIELD_SP(T0, 11, 12)) << 2;
+}
+
void OPPROTO op_alignaddr()
{
uint64_t tmp;
@@ -1601,6 +1905,440 @@
tmp = (*((uint64_t *)&DT0)) << ((env->gsr & 7) * 8);
tmp |= (*((uint64_t *)&DT1)) >> (64 - (env->gsr & 7) * 8);
- (*((uint64_t *)&DT0)) = tmp;
+ *((uint64_t *)&DT0) = tmp;
}
+
+void OPPROTO op_movl_FT0_0(void)
+{
+ *((uint32_t *)&FT0) = 0;
+}
+
+void OPPROTO op_movl_DT0_0(void)
+{
+ *((uint64_t *)&DT0) = 0;
+}
+
+void OPPROTO op_movl_FT0_1(void)
+{
+ *((uint32_t *)&FT0) = 0xffffffff;
+}
+
+void OPPROTO op_movl_DT0_1(void)
+{
+ *((uint64_t *)&DT0) = 0xffffffffffffffffULL;
+}
+
+void OPPROTO op_fnot(void)
+{
+ *(uint64_t *)&DT0 = ~*(uint64_t *)&DT1;
+}
+
+void OPPROTO op_fnots(void)
+{
+ *(uint32_t *)&FT0 = ~*(uint32_t *)&FT1;
+}
+
+void OPPROTO op_fnor(void)
+{
+ *(uint64_t *)&DT0 = ~(*(uint64_t *)&DT0 | *(uint64_t *)&DT1);
+}
+
+void OPPROTO op_fnors(void)
+{
+ *(uint32_t *)&FT0 = ~(*(uint32_t *)&FT0 | *(uint32_t *)&FT1);
+}
+
+void OPPROTO op_for(void)
+{
+ *(uint64_t *)&DT0 |= *(uint64_t *)&DT1;
+}
+
+void OPPROTO op_fors(void)
+{
+ *(uint32_t *)&FT0 |= *(uint32_t *)&FT1;
+}
+
+void OPPROTO op_fxor(void)
+{
+ *(uint64_t *)&DT0 ^= *(uint64_t *)&DT1;
+}
+
+void OPPROTO op_fxors(void)
+{
+ *(uint32_t *)&FT0 ^= *(uint32_t *)&FT1;
+}
+
+void OPPROTO op_fand(void)
+{
+ *(uint64_t *)&DT0 &= *(uint64_t *)&DT1;
+}
+
+void OPPROTO op_fands(void)
+{
+ *(uint32_t *)&FT0 &= *(uint32_t *)&FT1;
+}
+
+void OPPROTO op_fornot(void)
+{
+ *(uint64_t *)&DT0 = *(uint64_t *)&DT0 | ~*(uint64_t *)&DT1;
+}
+
+void OPPROTO op_fornots(void)
+{
+ *(uint32_t *)&FT0 = *(uint32_t *)&FT0 | ~*(uint32_t *)&FT1;
+}
+
+void OPPROTO op_fandnot(void)
+{
+ *(uint64_t *)&DT0 = *(uint64_t *)&DT0 & ~*(uint64_t *)&DT1;
+}
+
+void OPPROTO op_fandnots(void)
+{
+ *(uint32_t *)&FT0 = *(uint32_t *)&FT0 & ~*(uint32_t *)&FT1;
+}
+
+void OPPROTO op_fnand(void)
+{
+ *(uint64_t *)&DT0 = ~(*(uint64_t *)&DT0 & *(uint64_t *)&DT1);
+}
+
+void OPPROTO op_fnands(void)
+{
+ *(uint32_t *)&FT0 = ~(*(uint32_t *)&FT0 & *(uint32_t *)&FT1);
+}
+
+void OPPROTO op_fxnor(void)
+{
+ *(uint64_t *)&DT0 ^= ~*(uint64_t *)&DT1;
+}
+
+void OPPROTO op_fxnors(void)
+{
+ *(uint32_t *)&FT0 ^= ~*(uint32_t *)&FT1;
+}
+
+#ifdef WORDS_BIGENDIAN
+#define VIS_B64(n) b[7 - (n)]
+#define VIS_W64(n) w[3 - (n)]
+#define VIS_SW64(n) sw[3 - (n)]
+#define VIS_L64(n) l[1 - (n)]
+#define VIS_B32(n) b[3 - (n)]
+#define VIS_W32(n) w[1 - (n)]
+#else
+#define VIS_B64(n) b[n]
+#define VIS_W64(n) w[n]
+#define VIS_SW64(n) sw[n]
+#define VIS_L64(n) l[n]
+#define VIS_B32(n) b[n]
+#define VIS_W32(n) w[n]
#endif
+
+typedef union {
+ uint8_t b[8];
+ uint16_t w[4];
+ int16_t sw[4];
+ uint32_t l[2];
+ float64 d;
+} vis64;
+
+typedef union {
+ uint8_t b[4];
+ uint16_t w[2];
+ uint32_t l;
+ float32 f;
+} vis32;
+
+void OPPROTO op_fpmerge(void)
+{
+ vis64 s, d;
+
+ s.d = DT0;
+ d.d = DT1;
+
+ // Reverse calculation order to handle overlap
+ d.VIS_B64(7) = s.VIS_B64(3);
+ d.VIS_B64(6) = d.VIS_B64(3);
+ d.VIS_B64(5) = s.VIS_B64(2);
+ d.VIS_B64(4) = d.VIS_B64(2);
+ d.VIS_B64(3) = s.VIS_B64(1);
+ d.VIS_B64(2) = d.VIS_B64(1);
+ d.VIS_B64(1) = s.VIS_B64(0);
+ //d.VIS_B64(0) = d.VIS_B64(0);
+
+ DT0 = d.d;
+}
+
+void OPPROTO op_fmul8x16(void)
+{
+ vis64 s, d;
+ uint32_t tmp;
+
+ s.d = DT0;
+ d.d = DT1;
+
+#define PMUL(r) \
+ tmp = (int32_t)d.VIS_SW64(r) * (int32_t)s.VIS_B64(r); \
+ if ((tmp & 0xff) > 0x7f) \
+ tmp += 0x100; \
+ d.VIS_W64(r) = tmp >> 8;
+
+ PMUL(0);
+ PMUL(1);
+ PMUL(2);
+ PMUL(3);
+#undef PMUL
+
+ DT0 = d.d;
+}
+
+void OPPROTO op_fmul8x16al(void)
+{
+ vis64 s, d;
+ uint32_t tmp;
+
+ s.d = DT0;
+ d.d = DT1;
+
+#define PMUL(r) \
+ tmp = (int32_t)d.VIS_SW64(1) * (int32_t)s.VIS_B64(r); \
+ if ((tmp & 0xff) > 0x7f) \
+ tmp += 0x100; \
+ d.VIS_W64(r) = tmp >> 8;
+
+ PMUL(0);
+ PMUL(1);
+ PMUL(2);
+ PMUL(3);
+#undef PMUL
+
+ DT0 = d.d;
+}
+
+void OPPROTO op_fmul8x16au(void)
+{
+ vis64 s, d;
+ uint32_t tmp;
+
+ s.d = DT0;
+ d.d = DT1;
+
+#define PMUL(r) \
+ tmp = (int32_t)d.VIS_SW64(0) * (int32_t)s.VIS_B64(r); \
+ if ((tmp & 0xff) > 0x7f) \
+ tmp += 0x100; \
+ d.VIS_W64(r) = tmp >> 8;
+
+ PMUL(0);
+ PMUL(1);
+ PMUL(2);
+ PMUL(3);
+#undef PMUL
+
+ DT0 = d.d;
+}
+
+void OPPROTO op_fmul8sux16(void)
+{
+ vis64 s, d;
+ uint32_t tmp;
+
+ s.d = DT0;
+ d.d = DT1;
+
+#define PMUL(r) \
+ tmp = (int32_t)d.VIS_SW64(r) * ((int32_t)s.VIS_SW64(r) >> 8); \
+ if ((tmp & 0xff) > 0x7f) \
+ tmp += 0x100; \
+ d.VIS_W64(r) = tmp >> 8;
+
+ PMUL(0);
+ PMUL(1);
+ PMUL(2);
+ PMUL(3);
+#undef PMUL
+
+ DT0 = d.d;
+}
+
+void OPPROTO op_fmul8ulx16(void)
+{
+ vis64 s, d;
+ uint32_t tmp;
+
+ s.d = DT0;
+ d.d = DT1;
+
+#define PMUL(r) \
+ tmp = (int32_t)d.VIS_SW64(r) * ((uint32_t)s.VIS_B64(r * 2)); \
+ if ((tmp & 0xff) > 0x7f) \
+ tmp += 0x100; \
+ d.VIS_W64(r) = tmp >> 8;
+
+ PMUL(0);
+ PMUL(1);
+ PMUL(2);
+ PMUL(3);
+#undef PMUL
+
+ DT0 = d.d;
+}
+
+void OPPROTO op_fmuld8sux16(void)
+{
+ vis64 s, d;
+ uint32_t tmp;
+
+ s.d = DT0;
+ d.d = DT1;
+
+#define PMUL(r) \
+ tmp = (int32_t)d.VIS_SW64(r) * ((int32_t)s.VIS_SW64(r) >> 8); \
+ if ((tmp & 0xff) > 0x7f) \
+ tmp += 0x100; \
+ d.VIS_L64(r) = tmp;
+
+ // Reverse calculation order to handle overlap
+ PMUL(1);
+ PMUL(0);
+#undef PMUL
+
+ DT0 = d.d;
+}
+
+void OPPROTO op_fmuld8ulx16(void)
+{
+ vis64 s, d;
+ uint32_t tmp;
+
+ s.d = DT0;
+ d.d = DT1;
+
+#define PMUL(r) \
+ tmp = (int32_t)d.VIS_SW64(r) * ((uint32_t)s.VIS_B64(r * 2)); \
+ if ((tmp & 0xff) > 0x7f) \
+ tmp += 0x100; \
+ d.VIS_L64(r) = tmp;
+
+ // Reverse calculation order to handle overlap
+ PMUL(1);
+ PMUL(0);
+#undef PMUL
+
+ DT0 = d.d;
+}
+
+void OPPROTO op_fexpand(void)
+{
+ vis32 s;
+ vis64 d;
+
+ s.l = (uint32_t)(*(uint64_t *)&DT0 & 0xffffffff);
+ d.d = DT1;
+ d.VIS_L64(0) = s.VIS_W32(0) << 4;
+ d.VIS_L64(1) = s.VIS_W32(1) << 4;
+ d.VIS_L64(2) = s.VIS_W32(2) << 4;
+ d.VIS_L64(3) = s.VIS_W32(3) << 4;
+
+ DT0 = d.d;
+}
+
+#define VIS_OP(name, F) \
+ void OPPROTO name##16(void) \
+ { \
+ vis64 s, d; \
+ \
+ s.d = DT0; \
+ d.d = DT1; \
+ \
+ d.VIS_W64(0) = F(d.VIS_W64(0), s.VIS_W64(0)); \
+ d.VIS_W64(1) = F(d.VIS_W64(1), s.VIS_W64(1)); \
+ d.VIS_W64(2) = F(d.VIS_W64(2), s.VIS_W64(2)); \
+ d.VIS_W64(3) = F(d.VIS_W64(3), s.VIS_W64(3)); \
+ \
+ DT0 = d.d; \
+ } \
+ \
+ void OPPROTO name##16s(void) \
+ { \
+ vis32 s, d; \
+ \
+ s.f = FT0; \
+ d.f = FT1; \
+ \
+ d.VIS_W32(0) = F(d.VIS_W32(0), s.VIS_W32(0)); \
+ d.VIS_W32(1) = F(d.VIS_W32(1), s.VIS_W32(1)); \
+ \
+ FT0 = d.f; \
+ } \
+ \
+ void OPPROTO name##32(void) \
+ { \
+ vis64 s, d; \
+ \
+ s.d = DT0; \
+ d.d = DT1; \
+ \
+ d.VIS_L64(0) = F(d.VIS_L64(0), s.VIS_L64(0)); \
+ d.VIS_L64(1) = F(d.VIS_L64(1), s.VIS_L64(1)); \
+ \
+ DT0 = d.d; \
+ } \
+ \
+ void OPPROTO name##32s(void) \
+ { \
+ vis32 s, d; \
+ \
+ s.f = FT0; \
+ d.f = FT1; \
+ \
+ d.l = F(d.l, s.l); \
+ \
+ FT0 = d.f; \
+ }
+
+#define FADD(a, b) ((a) + (b))
+#define FSUB(a, b) ((a) - (b))
+VIS_OP(op_fpadd, FADD)
+VIS_OP(op_fpsub, FSUB)
+
+#define VIS_CMPOP(name, F) \
+ void OPPROTO name##16(void) \
+ { \
+ vis64 s, d; \
+ \
+ s.d = DT0; \
+ d.d = DT1; \
+ \
+ d.VIS_W64(0) = F(d.VIS_W64(0), s.VIS_W64(0))? 1: 0; \
+ d.VIS_W64(0) |= F(d.VIS_W64(1), s.VIS_W64(1))? 2: 0; \
+ d.VIS_W64(0) |= F(d.VIS_W64(2), s.VIS_W64(2))? 4: 0; \
+ d.VIS_W64(0) |= F(d.VIS_W64(3), s.VIS_W64(3))? 8: 0; \
+ \
+ DT0 = d.d; \
+ } \
+ \
+ void OPPROTO name##32(void) \
+ { \
+ vis64 s, d; \
+ \
+ s.d = DT0; \
+ d.d = DT1; \
+ \
+ d.VIS_L64(0) = F(d.VIS_L64(0), s.VIS_L64(0))? 1: 0; \
+ d.VIS_L64(0) |= F(d.VIS_L64(1), s.VIS_L64(1))? 2: 0; \
+ \
+ DT0 = d.d; \
+ }
+
+#define FCMPGT(a, b) ((a) > (b))
+#define FCMPEQ(a, b) ((a) == (b))
+#define FCMPLE(a, b) ((a) <= (b))
+#define FCMPNE(a, b) ((a) != (b))
+
+VIS_CMPOP(op_fcmpgt, FCMPGT)
+VIS_CMPOP(op_fcmpeq, FCMPEQ)
+VIS_CMPOP(op_fcmple, FCMPLE)
+VIS_CMPOP(op_fcmpne, FCMPNE)
+
+#endif
Modified: trunk/src/host/qemu-neo1973/target-sparc/op_helper.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-sparc/op_helper.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/target-sparc/op_helper.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -2,6 +2,7 @@
//#define DEBUG_PCALL
//#define DEBUG_MMU
+//#define DEBUG_UNALIGNED
void raise_exception(int tt)
{
@@ -9,10 +10,43 @@
cpu_loop_exit();
}
+void check_ieee_exceptions()
+{
+ T0 = get_float_exception_flags(&env->fp_status);
+ if (T0)
+ {
+ /* Copy IEEE 754 flags into FSR */
+ if (T0 & float_flag_invalid)
+ env->fsr |= FSR_NVC;
+ if (T0 & float_flag_overflow)
+ env->fsr |= FSR_OFC;
+ if (T0 & float_flag_underflow)
+ env->fsr |= FSR_UFC;
+ if (T0 & float_flag_divbyzero)
+ env->fsr |= FSR_DZC;
+ if (T0 & float_flag_inexact)
+ env->fsr |= FSR_NXC;
+
+ if ((env->fsr & FSR_CEXC_MASK) & ((env->fsr & FSR_TEM_MASK) >> 23))
+ {
+ /* Unmasked exception, generate a trap */
+ env->fsr |= FSR_FTT_IEEE_EXCP;
+ raise_exception(TT_FP_EXCP);
+ }
+ else
+ {
+ /* Accumulate exceptions */
+ env->fsr |= (env->fsr & FSR_CEXC_MASK) << 5;
+ }
+ }
+}
+
#ifdef USE_INT_TO_FLOAT_HELPERS
void do_fitos(void)
{
+ set_float_exception_flags(0, &env->fp_status);
FT0 = int32_to_float32(*((int32_t *)&FT1), &env->fp_status);
+ check_ieee_exceptions();
}
void do_fitod(void)
@@ -35,23 +69,29 @@
void do_fsqrts(void)
{
+ set_float_exception_flags(0, &env->fp_status);
FT0 = float32_sqrt(FT1, &env->fp_status);
+ check_ieee_exceptions();
}
void do_fsqrtd(void)
{
+ set_float_exception_flags(0, &env->fp_status);
DT0 = float64_sqrt(DT1, &env->fp_status);
+ check_ieee_exceptions();
}
-#define GEN_FCMP(name, size, reg1, reg2, FS) \
+#define GEN_FCMP(name, size, reg1, reg2, FS, TRAP) \
void glue(do_, name) (void) \
{ \
env->fsr &= ~((FSR_FCC1 | FSR_FCC0) << FS); \
switch (glue(size, _compare) (reg1, reg2, &env->fp_status)) { \
case float_relation_unordered: \
T0 = (FSR_FCC1 | FSR_FCC0) << FS; \
- if (env->fsr & FSR_NVM) { \
+ if ((env->fsr & FSR_NVM) || TRAP) { \
env->fsr |= T0; \
+ env->fsr |= FSR_NVC; \
+ env->fsr |= FSR_FTT_IEEE_EXCP; \
raise_exception(TT_FP_EXCP); \
} else { \
env->fsr |= FSR_NVA; \
@@ -70,18 +110,30 @@
env->fsr |= T0; \
}
-GEN_FCMP(fcmps, float32, FT0, FT1, 0);
-GEN_FCMP(fcmpd, float64, DT0, DT1, 0);
+GEN_FCMP(fcmps, float32, FT0, FT1, 0, 0);
+GEN_FCMP(fcmpd, float64, DT0, DT1, 0, 0);
+GEN_FCMP(fcmpes, float32, FT0, FT1, 0, 1);
+GEN_FCMP(fcmped, float64, DT0, DT1, 0, 1);
+
#ifdef TARGET_SPARC64
-GEN_FCMP(fcmps_fcc1, float32, FT0, FT1, 22);
-GEN_FCMP(fcmpd_fcc1, float64, DT0, DT1, 22);
+GEN_FCMP(fcmps_fcc1, float32, FT0, FT1, 22, 0);
+GEN_FCMP(fcmpd_fcc1, float64, DT0, DT1, 22, 0);
-GEN_FCMP(fcmps_fcc2, float32, FT0, FT1, 24);
-GEN_FCMP(fcmpd_fcc2, float64, DT0, DT1, 24);
+GEN_FCMP(fcmps_fcc2, float32, FT0, FT1, 24, 0);
+GEN_FCMP(fcmpd_fcc2, float64, DT0, DT1, 24, 0);
-GEN_FCMP(fcmps_fcc3, float32, FT0, FT1, 26);
-GEN_FCMP(fcmpd_fcc3, float64, DT0, DT1, 26);
+GEN_FCMP(fcmps_fcc3, float32, FT0, FT1, 26, 0);
+GEN_FCMP(fcmpd_fcc3, float64, DT0, DT1, 26, 0);
+
+GEN_FCMP(fcmpes_fcc1, float32, FT0, FT1, 22, 1);
+GEN_FCMP(fcmped_fcc1, float64, DT0, DT1, 22, 1);
+
+GEN_FCMP(fcmpes_fcc2, float32, FT0, FT1, 24, 1);
+GEN_FCMP(fcmped_fcc2, float64, DT0, DT1, 24, 1);
+
+GEN_FCMP(fcmpes_fcc3, float32, FT0, FT1, 26, 1);
+GEN_FCMP(fcmped_fcc3, float64, DT0, DT1, 26, 1);
#endif
#if defined(CONFIG_USER_ONLY)
@@ -615,6 +667,9 @@
{
unsigned int cwp;
+ if (env->psret == 1)
+ raise_exception(TT_ILL_INSN);
+
env->psret = 1;
cwp = (env->cwp + 1) & (NWINDOWS - 1);
if (env->wim & (1 << cwp)) {
@@ -655,7 +710,10 @@
#ifndef TARGET_SPARC64
void do_wrpsr()
{
- PUT_PSR(env, T0);
+ if ((T0 & PSR_CWP) >= NWINDOWS)
+ raise_exception(TT_ILL_INSN);
+ else
+ PUT_PSR(env, T0);
}
void do_rdpsr()
@@ -866,7 +924,11 @@
#if !defined(CONFIG_USER_ONLY)
+static void do_unaligned_access(target_ulong addr, int is_write, int is_user,
+ void *retaddr);
+
#define MMUSUFFIX _mmu
+#define ALIGNED_ONLY
#define GETPC() (__builtin_return_address(0))
#define SHIFT 0
@@ -881,6 +943,14 @@
#define SHIFT 3
#include "softmmu_template.h"
+static void do_unaligned_access(target_ulong addr, int is_write, int is_user,
+ void *retaddr)
+{
+#ifdef DEBUG_UNALIGNED
+ printf("Unaligned access to 0x%x from 0x%x\n", addr, env->pc);
+#endif
+ raise_exception(TT_UNALIGNED);
+}
/* 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
Modified: trunk/src/host/qemu-neo1973/target-sparc/translate.c
===================================================================
--- trunk/src/host/qemu-neo1973/target-sparc/translate.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/target-sparc/translate.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -25,9 +25,7 @@
Rest of V9 instructions, VIS instructions
NPC/PC static optimisations (use JUMP_TB when possible)
Optimize synthetic instructions
- Optional alignment check
128-bit float
- Tagged add/sub
*/
#include <stdarg.h>
@@ -56,6 +54,13 @@
struct TranslationBlock *tb;
} DisasContext;
+struct sparc_def_t {
+ const unsigned char *name;
+ target_ulong iu_version;
+ uint32_t fpu_version;
+ uint32_t mmu_version;
+};
+
static uint16_t *gen_opc_ptr;
static uint32_t *gen_opparam_ptr;
extern FILE *logfile;
@@ -84,7 +89,7 @@
#ifdef TARGET_SPARC64
#define DFPREG(r) (((r & 1) << 6) | (r & 0x1e))
#else
-#define DFPREG(r) (r)
+#define DFPREG(r) (r & 0x1e)
#endif
#ifdef USE_DIRECT_JUMP
@@ -103,7 +108,7 @@
static void disas_sparc_insn(DisasContext * dc);
-static GenOpFunc *gen_op_movl_TN_reg[2][32] = {
+static GenOpFunc * const gen_op_movl_TN_reg[2][32] = {
{
gen_op_movl_g0_T0,
gen_op_movl_g1_T0,
@@ -174,7 +179,7 @@
}
};
-static GenOpFunc *gen_op_movl_reg_TN[3][32] = {
+static GenOpFunc * const gen_op_movl_reg_TN[3][32] = {
{
gen_op_movl_T0_g0,
gen_op_movl_T0_g1,
@@ -279,7 +284,7 @@
}
};
-static GenOpFunc1 *gen_op_movl_TN_im[3] = {
+static GenOpFunc1 * const gen_op_movl_TN_im[3] = {
gen_op_movl_T0_im,
gen_op_movl_T1_im,
gen_op_movl_T2_im
@@ -294,7 +299,7 @@
#ifdef TARGET_SPARC64
#define GEN32(func, NAME) \
-static GenOpFunc *NAME ## _table [64] = { \
+static GenOpFunc * const NAME ## _table [64] = { \
NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3, \
NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \
NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \
@@ -314,7 +319,7 @@
}
#else
#define GEN32(func, NAME) \
-static GenOpFunc *NAME ## _table [32] = { \
+static GenOpFunc *const NAME ## _table [32] = { \
NAME ## 0, NAME ## 1, NAME ## 2, NAME ## 3, \
NAME ## 4, NAME ## 5, NAME ## 6, NAME ## 7, \
NAME ## 8, NAME ## 9, NAME ## 10, NAME ## 11, \
@@ -345,6 +350,7 @@
// 'a' versions allowed to user depending on asi
#if defined(CONFIG_USER_ONLY)
#define supervisor(dc) 0
+#define hypervisor(dc) 0
#define gen_op_ldst(name) gen_op_##name##_raw()
#define OP_LD_TABLE(width) \
static void gen_op_##width##a(int insn, int is_ld, int size, int sign) \
@@ -375,7 +381,7 @@
#else
#define gen_op_ldst(name) (*gen_op_##name[dc->mem_idx])()
#define OP_LD_TABLE(width) \
- static GenOpFunc *gen_op_##width[] = { \
+ static GenOpFunc * const gen_op_##width[] = { \
&gen_op_##width##_user, \
&gen_op_##width##_kernel, \
}; \
@@ -400,6 +406,7 @@
}
#define supervisor(dc) (dc->mem_idx == 1)
+#define hypervisor(dc) (dc->mem_idx == 2)
#endif
#else
#if defined(CONFIG_USER_ONLY)
@@ -409,7 +416,7 @@
#else
#define gen_op_ldst(name) (*gen_op_##name[dc->mem_idx])()
#define OP_LD_TABLE(width) \
-static GenOpFunc *gen_op_##width[] = { \
+static GenOpFunc * const gen_op_##width[] = { \
&gen_op_##width##_user, \
&gen_op_##width##_kernel, \
}; \
@@ -681,7 +688,7 @@
static GenOpFunc * const gen_cond[2][16] = {
{
- gen_op_eval_ba,
+ gen_op_eval_bn,
gen_op_eval_be,
gen_op_eval_ble,
gen_op_eval_bl,
@@ -689,7 +696,7 @@
gen_op_eval_bcs,
gen_op_eval_bneg,
gen_op_eval_bvs,
- gen_op_eval_bn,
+ gen_op_eval_ba,
gen_op_eval_bne,
gen_op_eval_bg,
gen_op_eval_bge,
@@ -700,7 +707,7 @@
},
{
#ifdef TARGET_SPARC64
- gen_op_eval_ba,
+ gen_op_eval_bn,
gen_op_eval_xbe,
gen_op_eval_xble,
gen_op_eval_xbl,
@@ -708,7 +715,7 @@
gen_op_eval_xbcs,
gen_op_eval_xbneg,
gen_op_eval_xbvs,
- gen_op_eval_bn,
+ gen_op_eval_ba,
gen_op_eval_xbne,
gen_op_eval_xbg,
gen_op_eval_xbge,
@@ -722,7 +729,7 @@
static GenOpFunc * const gen_fcond[4][16] = {
{
- gen_op_eval_ba,
+ gen_op_eval_bn,
gen_op_eval_fbne,
gen_op_eval_fblg,
gen_op_eval_fbul,
@@ -730,7 +737,7 @@
gen_op_eval_fbug,
gen_op_eval_fbg,
gen_op_eval_fbu,
- gen_op_eval_bn,
+ gen_op_eval_ba,
gen_op_eval_fbe,
gen_op_eval_fbue,
gen_op_eval_fbge,
@@ -741,7 +748,7 @@
},
#ifdef TARGET_SPARC64
{
- gen_op_eval_ba,
+ gen_op_eval_bn,
gen_op_eval_fbne_fcc1,
gen_op_eval_fblg_fcc1,
gen_op_eval_fbul_fcc1,
@@ -749,7 +756,7 @@
gen_op_eval_fbug_fcc1,
gen_op_eval_fbg_fcc1,
gen_op_eval_fbu_fcc1,
- gen_op_eval_bn,
+ gen_op_eval_ba,
gen_op_eval_fbe_fcc1,
gen_op_eval_fbue_fcc1,
gen_op_eval_fbge_fcc1,
@@ -759,7 +766,7 @@
gen_op_eval_fbo_fcc1,
},
{
- gen_op_eval_ba,
+ gen_op_eval_bn,
gen_op_eval_fbne_fcc2,
gen_op_eval_fblg_fcc2,
gen_op_eval_fbul_fcc2,
@@ -767,7 +774,7 @@
gen_op_eval_fbug_fcc2,
gen_op_eval_fbg_fcc2,
gen_op_eval_fbu_fcc2,
- gen_op_eval_bn,
+ gen_op_eval_ba,
gen_op_eval_fbe_fcc2,
gen_op_eval_fbue_fcc2,
gen_op_eval_fbge_fcc2,
@@ -777,7 +784,7 @@
gen_op_eval_fbo_fcc2,
},
{
- gen_op_eval_ba,
+ gen_op_eval_bn,
gen_op_eval_fbne_fcc3,
gen_op_eval_fblg_fcc3,
gen_op_eval_fbul_fcc3,
@@ -785,7 +792,7 @@
gen_op_eval_fbug_fcc3,
gen_op_eval_fbg_fcc3,
gen_op_eval_fbu_fcc3,
- gen_op_eval_bn,
+ gen_op_eval_ba,
gen_op_eval_fbe_fcc3,
gen_op_eval_fbue_fcc3,
gen_op_eval_fbge_fcc3,
@@ -937,6 +944,21 @@
gen_op_fcmpd_fcc2,
gen_op_fcmpd_fcc3,
};
+
+static GenOpFunc * const gen_fcmpes[4] = {
+ gen_op_fcmpes,
+ gen_op_fcmpes_fcc1,
+ gen_op_fcmpes_fcc2,
+ gen_op_fcmpes_fcc3,
+};
+
+static GenOpFunc * const gen_fcmped[4] = {
+ gen_op_fcmped,
+ gen_op_fcmped_fcc1,
+ gen_op_fcmped_fcc2,
+ gen_op_fcmped_fcc3,
+};
+
#endif
static int gen_trap_ifnofpu(DisasContext * dc)
@@ -1006,6 +1028,11 @@
do_fbranch(dc, target, insn, cc);
goto jmp_insn;
}
+#else
+ case 0x7: /* CBN+x */
+ {
+ goto ncp_insn;
+ }
#endif
case 0x2: /* BN+x */
{
@@ -1124,11 +1151,19 @@
rs1 = GET_FIELD(insn, 13, 17);
switch(rs1) {
case 0: /* rdy */
- gen_op_movtl_T0_env(offsetof(CPUSPARCState, y));
+#ifndef TARGET_SPARC64
+ case 0x01 ... 0x0e: /* undefined in the SPARCv8
+ manual, rdy on the microSPARC
+ II */
+ case 0x0f: /* stbar in the SPARCv8 manual,
+ rdy on the microSPARC II */
+ case 0x10 ... 0x1f: /* implementation-dependent in the
+ SPARCv8 manual, rdy on the
+ microSPARC II */
+#endif
+ gen_op_movtl_T0_env(offsetof(CPUSPARCState, y));
gen_movl_T0_reg(rd);
break;
- case 15: /* stbar / V9 membar */
- break; /* no effect? */
#ifdef TARGET_SPARC64
case 0x2: /* V9 rdccr */
gen_op_rdccr();
@@ -1154,6 +1189,8 @@
gen_op_movl_T0_env(offsetof(CPUSPARCState, fprs));
gen_movl_T0_reg(rd);
break;
+ case 0xf: /* V9 membar */
+ break; /* no effect */
case 0x13: /* Graphics Status */
if (gen_trap_ifnofpu(dc))
goto jmp_insn;
@@ -1183,14 +1220,40 @@
goto illegal_insn;
}
#if !defined(CONFIG_USER_ONLY)
+ } else if (xop == 0x29) { /* rdpsr / UA2005 rdhpr */
#ifndef TARGET_SPARC64
- } else if (xop == 0x29) { /* rdpsr / V9 unimp */
if (!supervisor(dc))
goto priv_insn;
gen_op_rdpsr();
+#else
+ if (!hypervisor(dc))
+ goto priv_insn;
+ rs1 = GET_FIELD(insn, 13, 17);
+ switch (rs1) {
+ case 0: // hpstate
+ // gen_op_rdhpstate();
+ break;
+ case 1: // htstate
+ // gen_op_rdhtstate();
+ break;
+ case 3: // hintp
+ gen_op_movl_T0_env(offsetof(CPUSPARCState, hintp));
+ break;
+ case 5: // htba
+ gen_op_movl_T0_env(offsetof(CPUSPARCState, htba));
+ break;
+ case 6: // hver
+ gen_op_movl_T0_env(offsetof(CPUSPARCState, hver));
+ break;
+ case 31: // hstick_cmpr
+ gen_op_movl_env_T0(offsetof(CPUSPARCState, hstick_cmpr));
+ break;
+ default:
+ goto illegal_insn;
+ }
+#endif
gen_movl_T0_reg(rd);
break;
-#endif
} else if (xop == 0x2a) { /* rdwim / V9 rdpr */
if (!supervisor(dc))
goto priv_insn;
@@ -1242,6 +1305,14 @@
case 14: // wstate
gen_op_movl_T0_env(offsetof(CPUSPARCState, wstate));
break;
+ case 16: // UA2005 gl
+ gen_op_movl_T0_env(offsetof(CPUSPARCState, gl));
+ break;
+ case 26: // UA2005 strand status
+ if (!hypervisor(dc))
+ goto priv_insn;
+ gen_op_movl_T0_env(offsetof(CPUSPARCState, ssr));
+ break;
case 31: // ver
gen_op_movtl_T0_env(offsetof(CPUSPARCState, version));
break;
@@ -1268,6 +1339,7 @@
} else if (xop == 0x34) { /* FPU Operations */
if (gen_trap_ifnofpu(dc))
goto jmp_insn;
+ gen_op_clear_ieee_excp_and_FTT();
rs1 = GET_FIELD(insn, 13, 17);
rs2 = GET_FIELD(insn, 27, 31);
xop = GET_FIELD(insn, 18, 26);
@@ -1455,6 +1527,7 @@
#endif
if (gen_trap_ifnofpu(dc))
goto jmp_insn;
+ gen_op_clear_ieee_excp_and_FTT();
rs1 = GET_FIELD(insn, 13, 17);
rs2 = GET_FIELD(insn, 27, 31);
xop = GET_FIELD(insn, 18, 26);
@@ -1632,18 +1705,18 @@
gen_op_load_fpr_FT0(rs1);
gen_op_load_fpr_FT1(rs2);
#ifdef TARGET_SPARC64
- gen_fcmps[rd & 3]();
+ gen_fcmpes[rd & 3]();
#else
- gen_op_fcmps(); /* XXX should trap if qNaN or sNaN */
+ gen_op_fcmpes();
#endif
break;
case 0x56: /* fcmped, V9 %fcc */
gen_op_load_fpr_DT0(DFPREG(rs1));
gen_op_load_fpr_DT1(DFPREG(rs2));
#ifdef TARGET_SPARC64
- gen_fcmpd[rd & 3]();
+ gen_fcmped[rd & 3]();
#else
- gen_op_fcmpd(); /* XXX should trap if qNaN or sNaN */
+ gen_op_fcmped();
#endif
break;
case 0x57: /* fcmpeq */
@@ -1687,7 +1760,7 @@
}
#endif
#ifdef TARGET_SPARC64
- } else if (xop == 0x25) { /* sll, V9 sllx ( == sll) */
+ } else if (xop == 0x25) { /* sll, V9 sllx */
rs1 = GET_FIELD(insn, 13, 17);
gen_movl_reg_T0(rs1);
if (IS_IMM) { /* immediate */
@@ -1697,7 +1770,10 @@
rs2 = GET_FIELD(insn, 27, 31);
gen_movl_reg_T1(rs2);
}
- gen_op_sll();
+ if (insn & (1 << 12))
+ gen_op_sllx();
+ else
+ gen_op_sll();
gen_movl_T0_reg(rd);
} else if (xop == 0x26) { /* srl, V9 srlx */
rs1 = GET_FIELD(insn, 13, 17);
@@ -1730,7 +1806,7 @@
gen_op_sra();
gen_movl_T0_reg(rd);
#endif
- } else if (xop < 0x38) {
+ } else if (xop < 0x36) {
rs1 = GET_FIELD(insn, 13, 17);
gen_movl_reg_T0(rs1);
if (IS_IMM) { /* immediate */
@@ -1833,10 +1909,21 @@
} else {
switch (xop) {
case 0x20: /* taddcc */
+ gen_op_tadd_T1_T0_cc();
+ gen_movl_T0_reg(rd);
+ break;
case 0x21: /* tsubcc */
+ gen_op_tsub_T1_T0_cc();
+ gen_movl_T0_reg(rd);
+ break;
case 0x22: /* taddcctv */
+ gen_op_tadd_T1_T0_ccTV();
+ gen_movl_T0_reg(rd);
+ break;
case 0x23: /* tsubcctv */
- goto illegal_insn;
+ gen_op_tsub_T1_T0_ccTV();
+ gen_movl_T0_reg(rd);
+ break;
case 0x24: /* mulscc */
gen_op_mulscc_T1_T0();
gen_movl_T0_reg(rd);
@@ -1862,7 +1949,17 @@
gen_op_xor_T1_T0();
gen_op_movtl_env_T0(offsetof(CPUSPARCState, y));
break;
-#ifdef TARGET_SPARC64
+#ifndef TARGET_SPARC64
+ case 0x01 ... 0x0f: /* undefined in the
+ SPARCv8 manual, nop
+ on the microSPARC
+ II */
+ case 0x10 ... 0x1f: /* implementation-dependent
+ in the SPARCv8
+ manual, nop on the
+ microSPARC II */
+ break;
+#else
case 0x2: /* V9 wrccr */
gen_op_wrccr();
break;
@@ -1870,7 +1967,13 @@
gen_op_movl_env_T0(offsetof(CPUSPARCState, asi));
break;
case 0x6: /* V9 wrfprs */
+ gen_op_xor_T1_T0();
gen_op_movl_env_T0(offsetof(CPUSPARCState, fprs));
+ save_state(dc);
+ gen_op_next_insn();
+ gen_op_movl_T0_0();
+ gen_op_exit_tb();
+ dc->is_br = 1;
break;
case 0xf: /* V9 sir, nop if user */
#if !defined(CONFIG_USER_ONLY)
@@ -1930,6 +2033,11 @@
case 1:
gen_op_restored();
break;
+ case 2: /* UA2005 allclean */
+ case 3: /* UA2005 otherw */
+ case 4: /* UA2005 normalw */
+ case 5: /* UA2005 invalw */
+ // XXX
default:
goto illegal_insn;
}
@@ -2001,6 +2109,14 @@
case 14: // wstate
gen_op_movl_env_T0(offsetof(CPUSPARCState, wstate));
break;
+ case 16: // UA2005 gl
+ gen_op_movl_env_T0(offsetof(CPUSPARCState, gl));
+ break;
+ case 26: // UA2005 strand status
+ if (!hypervisor(dc))
+ goto priv_insn;
+ gen_op_movl_env_T0(offsetof(CPUSPARCState, ssr));
+ break;
default:
goto illegal_insn;
}
@@ -2009,17 +2125,46 @@
#endif
}
break;
+ case 0x33: /* wrtbr, UA2005 wrhpr */
+ {
#ifndef TARGET_SPARC64
- case 0x33: /* wrtbr, V9 unimp */
- {
if (!supervisor(dc))
goto priv_insn;
gen_op_xor_T1_T0();
- gen_op_movtl_env_T0(offsetof(CPUSPARCState, tbr));
+ gen_op_movtl_env_T0(offsetof(CPUSPARCState, tbr));
+#else
+ if (!hypervisor(dc))
+ goto priv_insn;
+ gen_op_xor_T1_T0();
+ switch (rd) {
+ case 0: // hpstate
+ // XXX gen_op_wrhpstate();
+ save_state(dc);
+ gen_op_next_insn();
+ gen_op_movl_T0_0();
+ gen_op_exit_tb();
+ dc->is_br = 1;
+ break;
+ case 1: // htstate
+ // XXX gen_op_wrhtstate();
+ break;
+ case 3: // hintp
+ gen_op_movl_env_T0(offsetof(CPUSPARCState, hintp));
+ break;
+ case 5: // htba
+ gen_op_movl_env_T0(offsetof(CPUSPARCState, htba));
+ break;
+ case 31: // hstick_cmpr
+ gen_op_movl_env_T0(offsetof(CPUSPARCState, hstick_cmpr));
+ break;
+ case 6: // hver readonly
+ default:
+ goto illegal_insn;
+ }
+#endif
}
break;
#endif
-#endif
#ifdef TARGET_SPARC64
case 0x2c: /* V9 movcc */
{
@@ -2087,45 +2232,416 @@
gen_movl_T0_reg(rd);
break;
}
- case 0x36: /* UltraSparc shutdown, VIS */
- {
- int opf = GET_FIELD_SP(insn, 5, 13);
- rs1 = GET_FIELD(insn, 13, 17);
- rs2 = GET_FIELD(insn, 27, 31);
-
- switch (opf) {
- case 0x018: /* VIS I alignaddr */
- if (gen_trap_ifnofpu(dc))
- goto jmp_insn;
- gen_movl_reg_T0(rs1);
- gen_movl_reg_T1(rs2);
- gen_op_alignaddr();
- gen_movl_T0_reg(rd);
- break;
- case 0x01a: /* VIS I alignaddrl */
- if (gen_trap_ifnofpu(dc))
- goto jmp_insn;
- // XXX
- break;
- case 0x048: /* VIS I faligndata */
- if (gen_trap_ifnofpu(dc))
- goto jmp_insn;
- gen_op_load_fpr_DT0(rs1);
- gen_op_load_fpr_DT1(rs2);
- gen_op_faligndata();
- gen_op_store_DT0_fpr(rd);
- break;
- default:
- goto illegal_insn;
- }
- break;
- }
#endif
default:
goto illegal_insn;
}
}
+ } else if (xop == 0x36) { /* UltraSparc shutdown, VIS, V8 CPop1 */
#ifdef TARGET_SPARC64
+ int opf = GET_FIELD_SP(insn, 5, 13);
+ rs1 = GET_FIELD(insn, 13, 17);
+ rs2 = GET_FIELD(insn, 27, 31);
+ if (gen_trap_ifnofpu(dc))
+ goto jmp_insn;
+
+ switch (opf) {
+ case 0x000: /* VIS I edge8cc */
+ case 0x001: /* VIS II edge8n */
+ case 0x002: /* VIS I edge8lcc */
+ case 0x003: /* VIS II edge8ln */
+ case 0x004: /* VIS I edge16cc */
+ case 0x005: /* VIS II edge16n */
+ case 0x006: /* VIS I edge16lcc */
+ case 0x007: /* VIS II edge16ln */
+ case 0x008: /* VIS I edge32cc */
+ case 0x009: /* VIS II edge32n */
+ case 0x00a: /* VIS I edge32lcc */
+ case 0x00b: /* VIS II edge32ln */
+ // XXX
+ goto illegal_insn;
+ case 0x010: /* VIS I array8 */
+ gen_movl_reg_T0(rs1);
+ gen_movl_reg_T1(rs2);
+ gen_op_array8();
+ gen_movl_T0_reg(rd);
+ break;
+ case 0x012: /* VIS I array16 */
+ gen_movl_reg_T0(rs1);
+ gen_movl_reg_T1(rs2);
+ gen_op_array16();
+ gen_movl_T0_reg(rd);
+ break;
+ case 0x014: /* VIS I array32 */
+ gen_movl_reg_T0(rs1);
+ gen_movl_reg_T1(rs2);
+ gen_op_array32();
+ gen_movl_T0_reg(rd);
+ break;
+ case 0x018: /* VIS I alignaddr */
+ gen_movl_reg_T0(rs1);
+ gen_movl_reg_T1(rs2);
+ gen_op_alignaddr();
+ gen_movl_T0_reg(rd);
+ break;
+ case 0x019: /* VIS II bmask */
+ case 0x01a: /* VIS I alignaddrl */
+ // XXX
+ goto illegal_insn;
+ case 0x020: /* VIS I fcmple16 */
+ gen_op_load_fpr_DT0(rs1);
+ gen_op_load_fpr_DT1(rs2);
+ gen_op_fcmple16();
+ gen_op_store_DT0_fpr(rd);
+ break;
+ case 0x022: /* VIS I fcmpne16 */
+ gen_op_load_fpr_DT0(rs1);
+ gen_op_load_fpr_DT1(rs2);
+ gen_op_fcmpne16();
+ gen_op_store_DT0_fpr(rd);
+ break;
+ case 0x024: /* VIS I fcmple32 */
+ gen_op_load_fpr_DT0(rs1);
+ gen_op_load_fpr_DT1(rs2);
+ gen_op_fcmple32();
+ gen_op_store_DT0_fpr(rd);
+ break;
+ case 0x026: /* VIS I fcmpne32 */
+ gen_op_load_fpr_DT0(rs1);
+ gen_op_load_fpr_DT1(rs2);
+ gen_op_fcmpne32();
+ gen_op_store_DT0_fpr(rd);
+ break;
+ case 0x028: /* VIS I fcmpgt16 */
+ gen_op_load_fpr_DT0(rs1);
+ gen_op_load_fpr_DT1(rs2);
+ gen_op_fcmpgt16();
+ gen_op_store_DT0_fpr(rd);
+ break;
+ case 0x02a: /* VIS I fcmpeq16 */
+ gen_op_load_fpr_DT0(rs1);
+ gen_op_load_fpr_DT1(rs2);
+ gen_op_fcmpeq16();
+ gen_op_store_DT0_fpr(rd);
+ break;
+ case 0x02c: /* VIS I fcmpgt32 */
+ gen_op_load_fpr_DT0(rs1);
+ gen_op_load_fpr_DT1(rs2);
+ gen_op_fcmpgt32();
+ gen_op_store_DT0_fpr(rd);
+ break;
+ case 0x02e: /* VIS I fcmpeq32 */
+ gen_op_load_fpr_DT0(rs1);
+ gen_op_load_fpr_DT1(rs2);
+ gen_op_fcmpeq32();
+ gen_op_store_DT0_fpr(rd);
+ break;
+ case 0x031: /* VIS I fmul8x16 */
+ gen_op_load_fpr_DT0(rs1);
+ gen_op_load_fpr_DT1(rs2);
+ gen_op_fmul8x16();
+ gen_op_store_DT0_fpr(rd);
+ break;
+ case 0x033: /* VIS I fmul8x16au */
+ gen_op_load_fpr_DT0(rs1);
+ gen_op_load_fpr_DT1(rs2);
+ gen_op_fmul8x16au();
+ gen_op_store_DT0_fpr(rd);
+ break;
+ case 0x035: /* VIS I fmul8x16al */
+ gen_op_load_fpr_DT0(rs1);
+ gen_op_load_fpr_DT1(rs2);
+ gen_op_fmul8x16al();
+ gen_op_store_DT0_fpr(rd);
+ break;
+ case 0x036: /* VIS I fmul8sux16 */
+ gen_op_load_fpr_DT0(rs1);
+ gen_op_load_fpr_DT1(rs2);
+ gen_op_fmul8sux16();
+ gen_op_store_DT0_fpr(rd);
+ break;
+ case 0x037: /* VIS I fmul8ulx16 */
+ gen_op_load_fpr_DT0(rs1);
+ gen_op_load_fpr_DT1(rs2);
+ gen_op_fmul8ulx16();
+ gen_op_store_DT0_fpr(rd);
+ break;
+ case 0x038: /* VIS I fmuld8sux16 */
+ gen_op_load_fpr_DT0(rs1);
+ gen_op_load_fpr_DT1(rs2);
+ gen_op_fmuld8sux16();
+ gen_op_store_DT0_fpr(rd);
+ break;
+ case 0x039: /* VIS I fmuld8ulx16 */
+ gen_op_load_fpr_DT0(rs1);
+ gen_op_load_fpr_DT1(rs2);
+ gen_op_fmuld8ulx16();
+ gen_op_store_DT0_fpr(rd);
+ break;
+ case 0x03a: /* VIS I fpack32 */
+ case 0x03b: /* VIS I fpack16 */
+ case 0x03d: /* VIS I fpackfix */
+ case 0x03e: /* VIS I pdist */
+ // XXX
+ goto illegal_insn;
+ case 0x048: /* VIS I faligndata */
+ gen_op_load_fpr_DT0(rs1);
+ gen_op_load_fpr_DT1(rs2);
+ gen_op_faligndata();
+ gen_op_store_DT0_fpr(rd);
+ break;
+ case 0x04b: /* VIS I fpmerge */
+ gen_op_load_fpr_DT0(rs1);
+ gen_op_load_fpr_DT1(rs2);
+ gen_op_fpmerge();
+ gen_op_store_DT0_fpr(rd);
+ break;
+ case 0x04c: /* VIS II bshuffle */
+ // XXX
+ goto illegal_insn;
+ case 0x04d: /* VIS I fexpand */
+ gen_op_load_fpr_DT0(rs1);
+ gen_op_load_fpr_DT1(rs2);
+ gen_op_fexpand();
+ gen_op_store_DT0_fpr(rd);
+ break;
+ case 0x050: /* VIS I fpadd16 */
+ gen_op_load_fpr_DT0(rs1);
+ gen_op_load_fpr_DT1(rs2);
+ gen_op_fpadd16();
+ gen_op_store_DT0_fpr(rd);
+ break;
+ case 0x051: /* VIS I fpadd16s */
+ gen_op_load_fpr_FT0(rs1);
+ gen_op_load_fpr_FT1(rs2);
+ gen_op_fpadd16s();
+ gen_op_store_FT0_fpr(rd);
+ break;
+ case 0x052: /* VIS I fpadd32 */
+ gen_op_load_fpr_DT0(rs1);
+ gen_op_load_fpr_DT1(rs2);
+ gen_op_fpadd32();
+ gen_op_store_DT0_fpr(rd);
+ break;
+ case 0x053: /* VIS I fpadd32s */
+ gen_op_load_fpr_FT0(rs1);
+ gen_op_load_fpr_FT1(rs2);
+ gen_op_fpadd32s();
+ gen_op_store_FT0_fpr(rd);
+ break;
+ case 0x054: /* VIS I fpsub16 */
+ gen_op_load_fpr_DT0(rs1);
+ gen_op_load_fpr_DT1(rs2);
+ gen_op_fpsub16();
+ gen_op_store_DT0_fpr(rd);
+ break;
+ case 0x055: /* VIS I fpsub16s */
+ gen_op_load_fpr_FT0(rs1);
+ gen_op_load_fpr_FT1(rs2);
+ gen_op_fpsub16s();
+ gen_op_store_FT0_fpr(rd);
+ break;
+ case 0x056: /* VIS I fpsub32 */
+ gen_op_load_fpr_DT0(rs1);
+ gen_op_load_fpr_DT1(rs2);
+ gen_op_fpadd32();
+ gen_op_store_DT0_fpr(rd);
+ break;
+ case 0x057: /* VIS I fpsub32s */
+ gen_op_load_fpr_FT0(rs1);
+ gen_op_load_fpr_FT1(rs2);
+ gen_op_fpsub32s();
+ gen_op_store_FT0_fpr(rd);
+ break;
+ case 0x060: /* VIS I fzero */
+ gen_op_movl_DT0_0();
+ gen_op_store_DT0_fpr(rd);
+ break;
+ case 0x061: /* VIS I fzeros */
+ gen_op_movl_FT0_0();
+ gen_op_store_FT0_fpr(rd);
+ break;
+ case 0x062: /* VIS I fnor */
+ gen_op_load_fpr_DT0(rs1);
+ gen_op_load_fpr_DT1(rs2);
+ gen_op_fnor();
+ gen_op_store_DT0_fpr(rd);
+ break;
+ case 0x063: /* VIS I fnors */
+ gen_op_load_fpr_FT0(rs1);
+ gen_op_load_fpr_FT1(rs2);
+ gen_op_fnors();
+ gen_op_store_FT0_fpr(rd);
+ break;
+ case 0x064: /* VIS I fandnot2 */
+ gen_op_load_fpr_DT1(rs1);
+ gen_op_load_fpr_DT0(rs2);
+ gen_op_fandnot();
+ gen_op_store_DT0_fpr(rd);
+ break;
+ case 0x065: /* VIS I fandnot2s */
+ gen_op_load_fpr_FT1(rs1);
+ gen_op_load_fpr_FT0(rs2);
+ gen_op_fandnots();
+ gen_op_store_FT0_fpr(rd);
+ break;
+ case 0x066: /* VIS I fnot2 */
+ gen_op_load_fpr_DT1(rs2);
+ gen_op_fnot();
+ gen_op_store_DT0_fpr(rd);
+ break;
+ case 0x067: /* VIS I fnot2s */
+ gen_op_load_fpr_FT1(rs2);
+ gen_op_fnot();
+ gen_op_store_FT0_fpr(rd);
+ break;
+ case 0x068: /* VIS I fandnot1 */
+ gen_op_load_fpr_DT0(rs1);
+ gen_op_load_fpr_DT1(rs2);
+ gen_op_fandnot();
+ gen_op_store_DT0_fpr(rd);
+ break;
+ case 0x069: /* VIS I fandnot1s */
+ gen_op_load_fpr_FT0(rs1);
+ gen_op_load_fpr_FT1(rs2);
+ gen_op_fandnots();
+ gen_op_store_FT0_fpr(rd);
+ break;
+ case 0x06a: /* VIS I fnot1 */
+ gen_op_load_fpr_DT1(rs1);
+ gen_op_fnot();
+ gen_op_store_DT0_fpr(rd);
+ break;
+ case 0x06b: /* VIS I fnot1s */
+ gen_op_load_fpr_FT1(rs1);
+ gen_op_fnot();
+ gen_op_store_FT0_fpr(rd);
+ break;
+ case 0x06c: /* VIS I fxor */
+ gen_op_load_fpr_DT0(rs1);
+ gen_op_load_fpr_DT1(rs2);
+ gen_op_fxor();
+ gen_op_store_DT0_fpr(rd);
+ break;
+ case 0x06d: /* VIS I fxors */
+ gen_op_load_fpr_FT0(rs1);
+ gen_op_load_fpr_FT1(rs2);
+ gen_op_fxors();
+ gen_op_store_FT0_fpr(rd);
+ break;
+ case 0x06e: /* VIS I fnand */
+ gen_op_load_fpr_DT0(rs1);
+ gen_op_load_fpr_DT1(rs2);
+ gen_op_fnand();
+ gen_op_store_DT0_fpr(rd);
+ break;
+ case 0x06f: /* VIS I fnands */
+ gen_op_load_fpr_FT0(rs1);
+ gen_op_load_fpr_FT1(rs2);
+ gen_op_fnands();
+ gen_op_store_FT0_fpr(rd);
+ break;
+ case 0x070: /* VIS I fand */
+ gen_op_load_fpr_DT0(rs1);
+ gen_op_load_fpr_DT1(rs2);
+ gen_op_fand();
+ gen_op_store_DT0_fpr(rd);
+ break;
+ case 0x071: /* VIS I fands */
+ gen_op_load_fpr_FT0(rs1);
+ gen_op_load_fpr_FT1(rs2);
+ gen_op_fands();
+ gen_op_store_FT0_fpr(rd);
+ break;
+ case 0x072: /* VIS I fxnor */
+ gen_op_load_fpr_DT0(rs1);
+ gen_op_load_fpr_DT1(rs2);
+ gen_op_fxnor();
+ gen_op_store_DT0_fpr(rd);
+ break;
+ case 0x073: /* VIS I fxnors */
+ gen_op_load_fpr_FT0(rs1);
+ gen_op_load_fpr_FT1(rs2);
+ gen_op_fxnors();
+ gen_op_store_FT0_fpr(rd);
+ break;
+ case 0x074: /* VIS I fsrc1 */
+ gen_op_load_fpr_DT0(rs1);
+ gen_op_store_DT0_fpr(rd);
+ break;
+ case 0x075: /* VIS I fsrc1s */
+ gen_op_load_fpr_FT0(rs1);
+ gen_op_store_FT0_fpr(rd);
+ break;
+ case 0x076: /* VIS I fornot2 */
+ gen_op_load_fpr_DT1(rs1);
+ gen_op_load_fpr_DT0(rs2);
+ gen_op_fornot();
+ gen_op_store_DT0_fpr(rd);
+ break;
+ case 0x077: /* VIS I fornot2s */
+ gen_op_load_fpr_FT1(rs1);
+ gen_op_load_fpr_FT0(rs2);
+ gen_op_fornots();
+ gen_op_store_FT0_fpr(rd);
+ break;
+ case 0x078: /* VIS I fsrc2 */
+ gen_op_load_fpr_DT0(rs2);
+ gen_op_store_DT0_fpr(rd);
+ break;
+ case 0x079: /* VIS I fsrc2s */
+ gen_op_load_fpr_FT0(rs2);
+ gen_op_store_FT0_fpr(rd);
+ break;
+ case 0x07a: /* VIS I fornot1 */
+ gen_op_load_fpr_DT0(rs1);
+ gen_op_load_fpr_DT1(rs2);
+ gen_op_fornot();
+ gen_op_store_DT0_fpr(rd);
+ break;
+ case 0x07b: /* VIS I fornot1s */
+ gen_op_load_fpr_FT0(rs1);
+ gen_op_load_fpr_FT1(rs2);
+ gen_op_fornots();
+ gen_op_store_FT0_fpr(rd);
+ break;
+ case 0x07c: /* VIS I for */
+ gen_op_load_fpr_DT0(rs1);
+ gen_op_load_fpr_DT1(rs2);
+ gen_op_for();
+ gen_op_store_DT0_fpr(rd);
+ break;
+ case 0x07d: /* VIS I fors */
+ gen_op_load_fpr_FT0(rs1);
+ gen_op_load_fpr_FT1(rs2);
+ gen_op_fors();
+ gen_op_store_FT0_fpr(rd);
+ break;
+ case 0x07e: /* VIS I fone */
+ gen_op_movl_DT0_1();
+ gen_op_store_DT0_fpr(rd);
+ break;
+ case 0x07f: /* VIS I fones */
+ gen_op_movl_FT0_1();
+ gen_op_store_FT0_fpr(rd);
+ break;
+ case 0x080: /* VIS I shutdown */
+ case 0x081: /* VIS II siam */
+ // XXX
+ goto illegal_insn;
+ default:
+ goto illegal_insn;
+ }
+#else
+ goto ncp_insn;
+#endif
+ } else if (xop == 0x37) { /* V8 CPop2, V9 impdep2 */
+#ifdef TARGET_SPARC64
+ goto illegal_insn;
+#else
+ goto ncp_insn;
+#endif
+#ifdef TARGET_SPARC64
} else if (xop == 0x39) { /* V9 return */
rs1 = GET_FIELD(insn, 13, 17);
gen_movl_reg_T0(rs1);
@@ -2260,6 +2776,7 @@
{
unsigned int xop = GET_FIELD(insn, 7, 12);
rs1 = GET_FIELD(insn, 13, 17);
+ save_state(dc);
gen_movl_reg_T0(rs1);
if (IS_IMM) { /* immediate */
rs2 = GET_FIELDs(insn, 19, 31);
@@ -2283,8 +2800,8 @@
#endif
}
if (xop < 4 || (xop > 7 && xop < 0x14 && xop != 0x0e) || \
- (xop > 0x17 && xop < 0x1d ) || \
- (xop > 0x2c && xop < 0x33) || xop == 0x1f) {
+ (xop > 0x17 && xop <= 0x1d ) || \
+ (xop > 0x2c && xop <= 0x33) || xop == 0x1f) {
switch (xop) {
case 0x0: /* load word */
gen_op_ldst(ld);
@@ -2296,6 +2813,8 @@
gen_op_ldst(lduh);
break;
case 0x3: /* load double word */
+ if (rd & 1)
+ goto illegal_insn;
gen_op_ldst(ldd);
gen_movl_T0_reg(rd + 1);
break;
@@ -2315,6 +2834,8 @@
#if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64)
case 0x10: /* load word alternate */
#ifndef TARGET_SPARC64
+ if (IS_IMM)
+ goto illegal_insn;
if (!supervisor(dc))
goto priv_insn;
#endif
@@ -2322,6 +2843,8 @@
break;
case 0x11: /* load unsigned byte alternate */
#ifndef TARGET_SPARC64
+ if (IS_IMM)
+ goto illegal_insn;
if (!supervisor(dc))
goto priv_insn;
#endif
@@ -2329,6 +2852,8 @@
break;
case 0x12: /* load unsigned halfword alternate */
#ifndef TARGET_SPARC64
+ if (IS_IMM)
+ goto illegal_insn;
if (!supervisor(dc))
goto priv_insn;
#endif
@@ -2336,14 +2861,20 @@
break;
case 0x13: /* load double word alternate */
#ifndef TARGET_SPARC64
+ if (IS_IMM)
+ goto illegal_insn;
if (!supervisor(dc))
goto priv_insn;
#endif
+ if (rd & 1)
+ goto illegal_insn;
gen_op_ldda(insn, 1, 8, 0);
gen_movl_T0_reg(rd + 1);
break;
case 0x19: /* load signed byte alternate */
#ifndef TARGET_SPARC64
+ if (IS_IMM)
+ goto illegal_insn;
if (!supervisor(dc))
goto priv_insn;
#endif
@@ -2351,6 +2882,8 @@
break;
case 0x1a: /* load signed halfword alternate */
#ifndef TARGET_SPARC64
+ if (IS_IMM)
+ goto illegal_insn;
if (!supervisor(dc))
goto priv_insn;
#endif
@@ -2358,6 +2891,8 @@
break;
case 0x1d: /* ldstuba -- XXX: should be atomically */
#ifndef TARGET_SPARC64
+ if (IS_IMM)
+ goto illegal_insn;
if (!supervisor(dc))
goto priv_insn;
#endif
@@ -2365,6 +2900,8 @@
break;
case 0x1f: /* swap reg with alt. memory. Also atomically */
#ifndef TARGET_SPARC64
+ if (IS_IMM)
+ goto illegal_insn;
if (!supervisor(dc))
goto priv_insn;
#endif
@@ -2373,6 +2910,10 @@
break;
#ifndef TARGET_SPARC64
+ case 0x30: /* ldc */
+ case 0x31: /* ldcsr */
+ case 0x33: /* lddc */
+ goto ncp_insn;
/* avoid warnings */
(void) &gen_op_stfa;
(void) &gen_op_stdfa;
@@ -2454,6 +2995,8 @@
gen_op_ldst(sth);
break;
case 0x7:
+ if (rd & 1)
+ goto illegal_insn;
flush_T2(dc);
gen_movl_reg_T2(rd + 1);
gen_op_ldst(std);
@@ -2461,6 +3004,8 @@
#if !defined(CONFIG_USER_ONLY) || defined(TARGET_SPARC64)
case 0x14:
#ifndef TARGET_SPARC64
+ if (IS_IMM)
+ goto illegal_insn;
if (!supervisor(dc))
goto priv_insn;
#endif
@@ -2468,6 +3013,8 @@
break;
case 0x15:
#ifndef TARGET_SPARC64
+ if (IS_IMM)
+ goto illegal_insn;
if (!supervisor(dc))
goto priv_insn;
#endif
@@ -2475,6 +3022,8 @@
break;
case 0x16:
#ifndef TARGET_SPARC64
+ if (IS_IMM)
+ goto illegal_insn;
if (!supervisor(dc))
goto priv_insn;
#endif
@@ -2482,9 +3031,13 @@
break;
case 0x17:
#ifndef TARGET_SPARC64
+ if (IS_IMM)
+ goto illegal_insn;
if (!supervisor(dc))
goto priv_insn;
#endif
+ if (rd & 1)
+ goto illegal_insn;
flush_T2(dc);
gen_movl_reg_T2(rd + 1);
gen_op_stda(insn, 0, 8, 0);
@@ -2513,8 +3066,14 @@
gen_op_stfsr();
gen_op_ldst(stf);
break;
+#if !defined(CONFIG_USER_ONLY)
case 0x26: /* stdfq */
- goto nfpu_insn;
+ if (!supervisor(dc))
+ goto priv_insn;
+ if (gen_trap_ifnofpu(dc))
+ goto jmp_insn;
+ goto nfq_insn;
+#endif
case 0x27:
gen_op_load_fpr_DT0(DFPREG(rd));
gen_op_ldst(stdf);
@@ -2523,8 +3082,8 @@
goto illegal_insn;
}
} else if (xop > 0x33 && xop < 0x3f) {
+ switch (xop) {
#ifdef TARGET_SPARC64
- switch (xop) {
case 0x34: /* V9 stfa */
gen_op_stfa(insn, 0, 0, 0); // XXX
break;
@@ -2539,12 +3098,16 @@
break;
case 0x36: /* V9 stqfa */
goto nfpu_insn;
+#else
+ case 0x34: /* stc */
+ case 0x35: /* stcsr */
+ case 0x36: /* stdcq */
+ case 0x37: /* stdc */
+ goto ncp_insn;
+#endif
default:
goto illegal_insn;
}
-#else
- goto illegal_insn;
-#endif
}
else
goto illegal_insn;
@@ -2581,6 +3144,21 @@
save_state(dc);
gen_op_fpexception_im(FSR_FTT_UNIMPFPOP);
dc->is_br = 1;
+ return;
+#if !defined(CONFIG_USER_ONLY)
+ nfq_insn:
+ save_state(dc);
+ gen_op_fpexception_im(FSR_FTT_SEQ_ERROR);
+ dc->is_br = 1;
+ return;
+#endif
+#ifndef TARGET_SPARC64
+ ncp_insn:
+ save_state(dc);
+ gen_op_exception(TT_NCP_INSN);
+ dc->is_br = 1;
+ return;
+#endif
}
static inline int gen_intermediate_code_internal(TranslationBlock * tb,
@@ -2724,7 +3302,6 @@
void cpu_reset(CPUSPARCState *env)
{
- memset(env, 0, sizeof(*env));
tlb_flush(env, 1);
env->cwp = 0;
env->wim = 1;
@@ -2736,16 +3313,15 @@
env->cansave = NWINDOWS - 1;
#endif
#else
+ env->psret = 0;
env->psrs = 1;
env->psrps = 1;
- env->gregs[1] = ram_size;
#ifdef TARGET_SPARC64
env->pstate = PS_PRIV;
- env->version = GET_VER(env);
env->pc = 0x1fff0000000ULL;
#else
- env->mmuregs[0] = (0x04 << 24); /* Impl 0, ver 4, MMU disabled */
env->pc = 0xffd00000;
+ env->mmuregs[0] &= ~(MMU_E | MMU_NF);
#endif
env->npc = env->pc + 4;
#endif
@@ -2763,6 +3339,90 @@
return (env);
}
+static const sparc_def_t sparc_defs[] = {
+#ifdef TARGET_SPARC64
+ {
+ .name = "TI UltraSparc II",
+ .iu_version = ((0x17ULL << 48) | (0x11ULL << 32) | (0 << 24)
+ | (MAXTL << 8) | (NWINDOWS - 1)),
+ .fpu_version = 0x00000000,
+ .mmu_version = 0,
+ },
+#else
+ {
+ .name = "Fujitsu MB86904",
+ .iu_version = 0x04 << 24, /* Impl 0, ver 4 */
+ .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
+ .mmu_version = 0x04 << 24, /* Impl 0, ver 4 */
+ },
+ {
+ .name = "Fujitsu MB86907",
+ .iu_version = 0x05 << 24, /* Impl 0, ver 5 */
+ .fpu_version = 4 << 17, /* FPU version 4 (Meiko) */
+ .mmu_version = 0x05 << 24, /* Impl 0, ver 5 */
+ },
+ {
+ .name = "TI MicroSparc I",
+ .iu_version = 0x41000000,
+ .fpu_version = 4 << 17,
+ .mmu_version = 0x41000000,
+ },
+ {
+ .name = "TI SuperSparc II",
+ .iu_version = 0x40000000,
+ .fpu_version = 0 << 17,
+ .mmu_version = 0x04000000,
+ },
+ {
+ .name = "Ross RT620",
+ .iu_version = 0x1e000000,
+ .fpu_version = 1 << 17,
+ .mmu_version = 0x17000000,
+ },
+#endif
+};
+
+int sparc_find_by_name(const unsigned char *name, const sparc_def_t **def)
+{
+ int ret;
+ unsigned int i;
+
+ ret = -1;
+ *def = NULL;
+ for (i = 0; i < sizeof(sparc_defs) / sizeof(sparc_def_t); i++) {
+ if (strcasecmp(name, sparc_defs[i].name) == 0) {
+ *def = &sparc_defs[i];
+ ret = 0;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+void sparc_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...))
+{
+ unsigned int i;
+
+ for (i = 0; i < sizeof(sparc_defs) / sizeof(sparc_def_t); i++) {
+ (*cpu_fprintf)(f, "Sparc %16s IU " TARGET_FMT_lx " FPU %08x MMU %08x\n",
+ sparc_defs[i].name,
+ sparc_defs[i].iu_version,
+ sparc_defs[i].fpu_version,
+ sparc_defs[i].mmu_version);
+ }
+}
+
+int cpu_sparc_register (CPUSPARCState *env, const sparc_def_t *def)
+{
+ env->version = def->iu_version;
+ env->fsr = def->fpu_version;
+#if !defined(TARGET_SPARC64)
+ env->mmuregs[0] = def->mmu_version;
+#endif
+ return 0;
+}
+
#define GET_FLAG(a,b) ((env->psr & a)?b:'-')
void cpu_dump_state(CPUState *env, FILE *f,
@@ -2800,8 +3460,8 @@
cpu_fprintf(f, "\n");
}
#ifdef TARGET_SPARC64
- cpu_fprintf(f, "pstate: 0x%08x ccr: 0x%02x asi: 0x%02x tl: %d\n",
- env->pstate, GET_CCR(env), env->asi, env->tl);
+ cpu_fprintf(f, "pstate: 0x%08x ccr: 0x%02x asi: 0x%02x tl: %d fprs: %d\n",
+ env->pstate, GET_CCR(env), env->asi, env->tl, env->fprs);
cpu_fprintf(f, "cansave: %d canrestore: %d otherwin: %d wstate %d cleanwin %d cwp %d\n",
env->cansave, env->canrestore, env->otherwin, env->wstate,
env->cleanwin, NWINDOWS - 1 - env->cwp);
@@ -2816,7 +3476,7 @@
}
#if defined(CONFIG_USER_ONLY)
-target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
+target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
{
return addr;
}
@@ -2826,7 +3486,7 @@
int *access_index, target_ulong address, int rw,
int is_user);
-target_ulong cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
+target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
{
target_phys_addr_t phys_addr;
int prot, access_index;
Modified: trunk/src/host/qemu-neo1973/tests/Makefile
===================================================================
--- trunk/src/host/qemu-neo1973/tests/Makefile 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/tests/Makefile 2007-05-11 23:44:50 UTC (rev 1948)
@@ -13,7 +13,7 @@
TESTS+=sha1# test_path
#TESTS+=test_path
-QEMU=../i386-user/qemu-i386
+QEMU=../i386-linux-user/qemu-i386
all: $(TESTS)
@@ -83,7 +83,7 @@
arm-linux-gcc -Wall -g -O2 -c -o $@ $<
test-arm-iwmmxt: test-arm-iwmmxt.s
- cpp < $< | arm-palmte-linux-gnu-gcc -Wall -static -march=iwmmxt -mabi=aapcs -x assembler - -o $@
+ cpp < $< | arm-linux-gnu-gcc -Wall -static -march=iwmmxt -mabi=aapcs -x assembler - -o $@
# MIPS test
hello-mips: hello-mips.c
@@ -95,7 +95,7 @@
# XXX: find a way to compile easily a test for each arch
test2:
@for arch in i386 arm armeb sparc ppc mips mipsel; do \
- ../$${arch}-user/qemu-$${arch} $${arch}/ls -l linux-test.c ; \
+ ../$${arch}-linux-user/qemu-$${arch} $${arch}/ls -l linux-test.c ; \
done
clean:
Modified: trunk/src/host/qemu-neo1973/tests/test-arm-iwmmxt.s
===================================================================
--- trunk/src/host/qemu-neo1973/tests/test-arm-iwmmxt.s 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/tests/test-arm-iwmmxt.s 2007-05-11 23:44:50 UTC (rev 1948)
@@ -1,12 +1,11 @@
-@ Should print "testtesttesttest" if iwMMXt is functional.
+@ Checks whether iwMMXt is functional.
.code 32
-.align 4
.globl main
main:
-adr r0, data0
-adr r1, data1
-adr r2, data2
+ldr r0, =data0
+ldr r1, =data1
+ldr r2, =data2
#ifndef FPA
wldrd wr0, [r0, #0]
wldrd wr1, [r0, #8]
@@ -41,9 +40,10 @@
mov r0, #0
swi #0x900001
+.data
data0:
.string "aaaabbbbccccdddd"
data1:
.string "bbbbccccddddeeee"
data2:
-.string "sdrssdrssdrssdrs\n"
+.string "hvLLWs\x1fsdrs9\x1fNJ-\n"
Modified: trunk/src/host/qemu-neo1973/tests/test-i386.c
===================================================================
--- trunk/src/host/qemu-neo1973/tests/test-i386.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/tests/test-i386.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -2583,6 +2583,41 @@
#endif
+#define TEST_CONV_RAX(op)\
+{\
+ unsigned long a, r;\
+ a = i2l(0x8234a6f8);\
+ r = a;\
+ asm volatile(#op : "=a" (r) : "0" (r));\
+ printf("%-10s A=" FMTLX " R=" FMTLX "\n", #op, a, r);\
+}
+
+#define TEST_CONV_RAX_RDX(op)\
+{\
+ unsigned long a, d, r, rh; \
+ a = i2l(0x8234a6f8);\
+ d = i2l(0x8345a1f2);\
+ r = a;\
+ rh = d;\
+ asm volatile(#op : "=a" (r), "=d" (rh) : "0" (r), "1" (rh)); \
+ printf("%-10s A=" FMTLX " R=" FMTLX ":" FMTLX "\n", #op, a, r, rh); \
+}
+
+void test_conv(void)
+{
+ TEST_CONV_RAX(cbw);
+ TEST_CONV_RAX(cwde);
+#if defined(__x86_64__)
+ TEST_CONV_RAX(cdqe);
+#endif
+
+ TEST_CONV_RAX_RDX(cwd);
+ TEST_CONV_RAX_RDX(cdq);
+#if defined(__x86_64__)
+ TEST_CONV_RAX_RDX(cqo);
+#endif
+}
+
extern void *__start_initcall;
extern void *__stop_initcall;
@@ -2621,6 +2656,7 @@
test_single_step();
#endif
test_enter();
+ test_conv();
#ifdef TEST_SSE
test_sse();
test_fxsave();
Modified: trunk/src/host/qemu-neo1973/translate-all.c
===================================================================
--- trunk/src/host/qemu-neo1973/translate-all.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/translate-all.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -308,6 +308,8 @@
env->PC = gen_opc_pc[j];
env->hflags &= ~MIPS_HFLAG_BMASK;
env->hflags |= gen_opc_hflags[j];
+#elif defined(TARGET_ALPHA)
+ env->pc = gen_opc_pc[j];
#endif
return 0;
}
Added: trunk/src/host/qemu-neo1973/uboot_image.h
===================================================================
--- trunk/src/host/qemu-neo1973/uboot_image.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/uboot_image.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,160 @@
+/*
+ * (C) Copyright 2000-2005
+ * Wolfgang Denk, DENX Software Engineering, wd at denx.de.
+ *
+ * See file CREDITS for list of people who contributed to this
+ * project.
+ *
+ * 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
+ *
+ ********************************************************************
+ * NOTE: This header file defines an interface to U-Boot. Including
+ * this (unmodified) header file in another file is considered normal
+ * use of U-Boot, and does *not* fall under the heading of "derived
+ * work".
+ ********************************************************************
+ */
+
+#ifndef __UBOOT_IMAGE_H__
+#define __UBOOT_IMAGE_H__
+
+/*
+ * Operating System Codes
+ */
+#define IH_OS_INVALID 0 /* Invalid OS */
+#define IH_OS_OPENBSD 1 /* OpenBSD */
+#define IH_OS_NETBSD 2 /* NetBSD */
+#define IH_OS_FREEBSD 3 /* FreeBSD */
+#define IH_OS_4_4BSD 4 /* 4.4BSD */
+#define IH_OS_LINUX 5 /* Linux */
+#define IH_OS_SVR4 6 /* SVR4 */
+#define IH_OS_ESIX 7 /* Esix */
+#define IH_OS_SOLARIS 8 /* Solaris */
+#define IH_OS_IRIX 9 /* Irix */
+#define IH_OS_SCO 10 /* SCO */
+#define IH_OS_DELL 11 /* Dell */
+#define IH_OS_NCR 12 /* NCR */
+#define IH_OS_LYNXOS 13 /* LynxOS */
+#define IH_OS_VXWORKS 14 /* VxWorks */
+#define IH_OS_PSOS 15 /* pSOS */
+#define IH_OS_QNX 16 /* QNX */
+#define IH_OS_U_BOOT 17 /* Firmware */
+#define IH_OS_RTEMS 18 /* RTEMS */
+#define IH_OS_ARTOS 19 /* ARTOS */
+#define IH_OS_UNITY 20 /* Unity OS */
+
+/*
+ * CPU Architecture Codes (supported by Linux)
+ */
+#define IH_CPU_INVALID 0 /* Invalid CPU */
+#define IH_CPU_ALPHA 1 /* Alpha */
+#define IH_CPU_ARM 2 /* ARM */
+#define IH_CPU_I386 3 /* Intel x86 */
+#define IH_CPU_IA64 4 /* IA64 */
+#define IH_CPU_MIPS 5 /* MIPS */
+#define IH_CPU_MIPS64 6 /* MIPS 64 Bit */
+#define IH_CPU_PPC 7 /* PowerPC */
+#define IH_CPU_S390 8 /* IBM S390 */
+#define IH_CPU_SH 9 /* SuperH */
+#define IH_CPU_SPARC 10 /* Sparc */
+#define IH_CPU_SPARC64 11 /* Sparc 64 Bit */
+#define IH_CPU_M68K 12 /* M68K */
+#define IH_CPU_NIOS 13 /* Nios-32 */
+#define IH_CPU_MICROBLAZE 14 /* MicroBlaze */
+#define IH_CPU_NIOS2 15 /* Nios-II */
+#define IH_CPU_BLACKFIN 16 /* Blackfin */
+#define IH_CPU_AVR32 17 /* AVR32 */
+
+/*
+ * Image Types
+ *
+ * "Standalone Programs" are directly runnable in the environment
+ * provided by U-Boot; it is expected that (if they behave
+ * well) you can continue to work in U-Boot after return from
+ * the Standalone Program.
+ * "OS Kernel Images" are usually images of some Embedded OS which
+ * will take over control completely. Usually these programs
+ * will install their own set of exception handlers, device
+ * drivers, set up the MMU, etc. - this means, that you cannot
+ * expect to re-enter U-Boot except by resetting the CPU.
+ * "RAMDisk Images" are more or less just data blocks, and their
+ * parameters (address, size) are passed to an OS kernel that is
+ * being started.
+ * "Multi-File Images" contain several images, typically an OS
+ * (Linux) kernel image and one or more data images like
+ * RAMDisks. This construct is useful for instance when you want
+ * to boot over the network using BOOTP etc., where the boot
+ * server provides just a single image file, but you want to get
+ * for instance an OS kernel and a RAMDisk image.
+ *
+ * "Multi-File Images" start with a list of image sizes, each
+ * image size (in bytes) specified by an "uint32_t" in network
+ * byte order. This list is terminated by an "(uint32_t)0".
+ * Immediately after the terminating 0 follow the images, one by
+ * one, all aligned on "uint32_t" boundaries (size rounded up to
+ * a multiple of 4 bytes - except for the last file).
+ *
+ * "Firmware Images" are binary images containing firmware (like
+ * U-Boot or FPGA images) which usually will be programmed to
+ * flash memory.
+ *
+ * "Script files" are command sequences that will be executed by
+ * U-Boot's command interpreter; this feature is especially
+ * useful when you configure U-Boot to use a real shell (hush)
+ * as command interpreter (=> Shell Scripts).
+ */
+
+#define IH_TYPE_INVALID 0 /* Invalid Image */
+#define IH_TYPE_STANDALONE 1 /* Standalone Program */
+#define IH_TYPE_KERNEL 2 /* OS Kernel Image */
+#define IH_TYPE_RAMDISK 3 /* RAMDisk Image */
+#define IH_TYPE_MULTI 4 /* Multi-File Image */
+#define IH_TYPE_FIRMWARE 5 /* Firmware Image */
+#define IH_TYPE_SCRIPT 6 /* Script file */
+#define IH_TYPE_FILESYSTEM 7 /* Filesystem Image (any type) */
+#define IH_TYPE_FLATDT 8 /* Binary Flat Device Tree Blob */
+
+/*
+ * Compression Types
+ */
+#define IH_COMP_NONE 0 /* No Compression Used */
+#define IH_COMP_GZIP 1 /* gzip Compression Used */
+#define IH_COMP_BZIP2 2 /* bzip2 Compression Used */
+
+#define IH_MAGIC 0x27051956 /* Image Magic Number */
+#define IH_NMLEN 32 /* Image Name Length */
+
+/*
+ * all data in network byte order (aka natural aka bigendian)
+ */
+
+typedef struct uboot_image_header {
+ uint32_t ih_magic; /* Image Header Magic Number */
+ uint32_t ih_hcrc; /* Image Header CRC Checksum */
+ uint32_t ih_time; /* Image Creation Timestamp */
+ uint32_t ih_size; /* Image Data Size */
+ uint32_t ih_load; /* Data Load Address */
+ uint32_t ih_ep; /* Entry Point Address */
+ uint32_t ih_dcrc; /* Image Data CRC Checksum */
+ uint8_t ih_os; /* Operating System */
+ uint8_t ih_arch; /* CPU architecture */
+ uint8_t ih_type; /* Image Type */
+ uint8_t ih_comp; /* Compression Type */
+ uint8_t ih_name[IH_NMLEN]; /* Image Name */
+} uboot_image_header_t;
+
+
+#endif /* __IMAGE_H__ */
Modified: trunk/src/host/qemu-neo1973/vl.c
===================================================================
--- trunk/src/host/qemu-neo1973/vl.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/vl.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -1,7 +1,7 @@
/*
* QEMU System Emulator
*
- * Copyright (c) 2003-2006 Fabrice Bellard
+ * Copyright (c) 2003-2007 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
@@ -55,6 +55,22 @@
#include <malloc.h>
#include <linux/rtc.h>
#include <linux/ppdev.h>
+#include <linux/parport.h>
+#else
+#include <sys/stat.h>
+#include <sys/ethernet.h>
+#include <sys/sockio.h>
+#include <arpa/inet.h>
+#include <netinet/arp.h>
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip_icmp.h> // must come after ip.h
+#include <netinet/udp.h>
+#include <netinet/tcp.h>
+#include <net/if.h>
+#include <syslog.h>
+#include <stropts.h>
#endif
#endif
#endif
@@ -122,10 +138,12 @@
/* Note: bs_table[MAX_DISKS] is a dummy block driver if none available
to store the VM snapshots */
BlockDriverState *bs_table[MAX_DISKS + 1], *fd_table[MAX_FD];
+BlockDriverState *pflash_table[MAX_PFLASH];
+BlockDriverState *sd_bdrv;
+BlockDriverState *mtd_bdrv;
/* point to the block driver where the snapshots are managed */
BlockDriverState *bs_snapshots;
int vga_ram_size;
-int bios_size;
static DisplayState display_state;
int nographic;
const char* keyboard_layout = NULL;
@@ -139,15 +157,18 @@
int vm_running;
int rtc_utc = 1;
int cirrus_vga_enabled = 1;
+int vmsvga_enabled = 0;
#ifdef TARGET_SPARC
int graphic_width = 1024;
int graphic_height = 768;
+int graphic_depth = 8;
#else
int graphic_width = 800;
int graphic_height = 600;
+int graphic_depth = 15;
#endif
-int graphic_depth = 15;
int full_screen = 0;
+int no_frame = 0;
int no_quit = 0;
CharDriverState *serial_hds[MAX_SERIAL_PORTS];
CharDriverState *parallel_hds[MAX_PARALLEL_PORTS];
@@ -169,13 +190,17 @@
int fd_bootchk = 1;
int no_reboot = 0;
int cursor_hide = 1;
-int snapshot = 0;
-const char *sd_filename = 0;
-const char *mtd_filename = 0;
int graphic_rotate = 0;
int daemonize = 0;
const char *option_rom[MAX_OPTION_ROMS];
int nb_option_roms;
+int semihosting_enabled = 0;
+int autostart = 1;
+const char *qemu_name;
+#ifdef TARGET_SPARC
+unsigned int nb_prom_envs = 0;
+const char *prom_envs[MAX_PROM_ENVS];
+#endif
/***********************************************************/
/* x86 ISA bus support */
@@ -186,7 +211,7 @@
uint32_t default_ioport_readb(void *opaque, uint32_t address)
{
#ifdef DEBUG_UNUSED_IOPORT
- fprintf(stderr, "inb: port=0x%04x\n", address);
+ fprintf(stderr, "unused inb: port=0x%04x\n", address);
#endif
return 0xff;
}
@@ -194,7 +219,7 @@
void default_ioport_writeb(void *opaque, uint32_t address, uint32_t data)
{
#ifdef DEBUG_UNUSED_IOPORT
- fprintf(stderr, "outb: port=0x%04x data=0x%02x\n", address, data);
+ fprintf(stderr, "unused outb: port=0x%04x data=0x%02x\n", address, data);
#endif
}
@@ -218,7 +243,7 @@
uint32_t default_ioport_readl(void *opaque, uint32_t address)
{
#ifdef DEBUG_UNUSED_IOPORT
- fprintf(stderr, "inl: port=0x%04x\n", address);
+ fprintf(stderr, "unused inl: port=0x%04x\n", address);
#endif
return 0xffffffff;
}
@@ -226,7 +251,7 @@
void default_ioport_writel(void *opaque, uint32_t address, uint32_t data)
{
#ifdef DEBUG_UNUSED_IOPORT
- fprintf(stderr, "outl: port=0x%04x data=0x%02x\n", address, data);
+ fprintf(stderr, "unused outl: port=0x%04x data=0x%02x\n", address, data);
#endif
}
@@ -1132,11 +1157,17 @@
/***********************************************************/
/* character device */
+static void qemu_chr_event(CharDriverState *s, int event)
+{
+ if (!s->chr_event)
+ return;
+ s->chr_event(s->handler_opaque, event);
+}
+
static void qemu_chr_reset_bh(void *opaque)
{
CharDriverState *s = opaque;
- if (s->chr_event)
- s->chr_event(s, CHR_EVENT_RESET);
+ qemu_chr_event(s, CHR_EVENT_RESET);
qemu_bh_delete(s->bh);
s->bh = NULL;
}
@@ -1161,6 +1192,19 @@
return s->chr_ioctl(s, cmd, arg);
}
+int qemu_chr_can_read(CharDriverState *s)
+{
+ if (!s->chr_can_read)
+ return 0;
+ return s->chr_can_read(s->handler_opaque);
+}
+
+void qemu_chr_read(CharDriverState *s, uint8_t *buf, int len)
+{
+ s->chr_read(s->handler_opaque, buf, len);
+}
+
+
void qemu_chr_printf(CharDriverState *s, const char *fmt, ...)
{
char buf[4096];
@@ -1177,41 +1221,248 @@
s->chr_send_event(s, event);
}
-void qemu_chr_add_read_handler(CharDriverState *s,
- IOCanRWHandler *fd_can_read,
- IOReadHandler *fd_read, void *opaque)
+void qemu_chr_add_handlers(CharDriverState *s,
+ IOCanRWHandler *fd_can_read,
+ IOReadHandler *fd_read,
+ IOEventHandler *fd_event,
+ void *opaque)
{
- s->chr_add_read_handler(s, fd_can_read, fd_read, opaque);
+ s->chr_can_read = fd_can_read;
+ s->chr_read = fd_read;
+ s->chr_event = fd_event;
+ s->handler_opaque = opaque;
+ if (s->chr_update_read_handler)
+ s->chr_update_read_handler(s);
}
-void qemu_chr_add_event_handler(CharDriverState *s, IOEventHandler *chr_event)
+static int null_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
{
- s->chr_event = chr_event;
+ return len;
}
-static int null_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
+static CharDriverState *qemu_chr_open_null(void)
{
- return len;
+ CharDriverState *chr;
+
+ chr = qemu_mallocz(sizeof(CharDriverState));
+ if (!chr)
+ return NULL;
+ chr->chr_write = null_chr_write;
+ return chr;
}
-static void null_chr_add_read_handler(CharDriverState *chr,
- IOCanRWHandler *fd_can_read,
- IOReadHandler *fd_read, void *opaque)
+/* MUX driver for serial I/O splitting */
+static int term_timestamps;
+static int64_t term_timestamps_start;
+#define MAX_MUX 4
+typedef struct {
+ IOCanRWHandler *chr_can_read[MAX_MUX];
+ IOReadHandler *chr_read[MAX_MUX];
+ IOEventHandler *chr_event[MAX_MUX];
+ void *ext_opaque[MAX_MUX];
+ CharDriverState *drv;
+ int mux_cnt;
+ int term_got_escape;
+ int max_size;
+} MuxDriver;
+
+
+static int mux_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
{
+ MuxDriver *d = chr->opaque;
+ int ret;
+ if (!term_timestamps) {
+ ret = d->drv->chr_write(d->drv, buf, len);
+ } else {
+ int i;
+
+ ret = 0;
+ for(i = 0; i < len; i++) {
+ ret += d->drv->chr_write(d->drv, buf+i, 1);
+ if (buf[i] == '\n') {
+ char buf1[64];
+ int64_t ti;
+ int secs;
+
+ ti = get_clock();
+ if (term_timestamps_start == -1)
+ term_timestamps_start = ti;
+ ti -= term_timestamps_start;
+ secs = ti / 1000000000;
+ snprintf(buf1, sizeof(buf1),
+ "[%02d:%02d:%02d.%03d] ",
+ secs / 3600,
+ (secs / 60) % 60,
+ secs % 60,
+ (int)((ti / 1000000) % 1000));
+ d->drv->chr_write(d->drv, buf1, strlen(buf1));
+ }
+ }
+ }
+ return ret;
}
-static CharDriverState *qemu_chr_open_null(void)
+static char *mux_help[] = {
+ "% h print this help\n\r",
+ "% x exit emulator\n\r",
+ "% s save disk data back to file (if -snapshot)\n\r",
+ "% t toggle console timestamps\n\r"
+ "% b send break (magic sysrq)\n\r",
+ "% c switch between console and monitor\n\r",
+ "% % sends %\n\r",
+ NULL
+};
+
+static int term_escape_char = 0x01; /* ctrl-a is used for escape */
+static void mux_print_help(CharDriverState *chr)
{
+ int i, j;
+ char ebuf[15] = "Escape-Char";
+ char cbuf[50] = "\n\r";
+
+ if (term_escape_char > 0 && term_escape_char < 26) {
+ sprintf(cbuf,"\n\r");
+ sprintf(ebuf,"C-%c", term_escape_char - 1 + 'a');
+ } else {
+ sprintf(cbuf,"\n\rEscape-Char set to Ascii: 0x%02x\n\r\n\r", term_escape_char);
+ }
+ chr->chr_write(chr, cbuf, strlen(cbuf));
+ for (i = 0; mux_help[i] != NULL; i++) {
+ for (j=0; mux_help[i][j] != '\0'; j++) {
+ if (mux_help[i][j] == '%')
+ chr->chr_write(chr, ebuf, strlen(ebuf));
+ else
+ chr->chr_write(chr, &mux_help[i][j], 1);
+ }
+ }
+}
+
+static int mux_proc_byte(CharDriverState *chr, MuxDriver *d, int ch)
+{
+ if (d->term_got_escape) {
+ d->term_got_escape = 0;
+ if (ch == term_escape_char)
+ goto send_char;
+ switch(ch) {
+ case '?':
+ case 'h':
+ mux_print_help(chr);
+ break;
+ case 'x':
+ {
+ char *term = "QEMU: Terminated\n\r";
+ chr->chr_write(chr,term,strlen(term));
+ exit(0);
+ break;
+ }
+ case 's':
+ {
+ int i;
+ for (i = 0; i < MAX_DISKS; i++) {
+ if (bs_table[i])
+ bdrv_commit(bs_table[i]);
+ }
+ }
+ break;
+ case 'b':
+ if (chr->chr_event)
+ chr->chr_event(chr->opaque, CHR_EVENT_BREAK);
+ break;
+ case 'c':
+ /* Switch to the next registered device */
+ chr->focus++;
+ if (chr->focus >= d->mux_cnt)
+ chr->focus = 0;
+ break;
+ case 't':
+ term_timestamps = !term_timestamps;
+ term_timestamps_start = -1;
+ break;
+ }
+ } else if (ch == term_escape_char) {
+ d->term_got_escape = 1;
+ } else {
+ send_char:
+ return 1;
+ }
+ return 0;
+}
+
+static int mux_chr_can_read(void *opaque)
+{
+ CharDriverState *chr = opaque;
+ MuxDriver *d = chr->opaque;
+ if (d->chr_can_read[chr->focus])
+ return d->chr_can_read[chr->focus](d->ext_opaque[chr->focus]);
+ return 0;
+}
+
+static void mux_chr_read(void *opaque, const uint8_t *buf, int size)
+{
+ CharDriverState *chr = opaque;
+ MuxDriver *d = chr->opaque;
+ int i;
+ for(i = 0; i < size; i++)
+ if (mux_proc_byte(chr, d, buf[i]))
+ d->chr_read[chr->focus](d->ext_opaque[chr->focus], &buf[i], 1);
+}
+
+static void mux_chr_event(void *opaque, int event)
+{
+ CharDriverState *chr = opaque;
+ MuxDriver *d = chr->opaque;
+ int i;
+
+ /* Send the event to all registered listeners */
+ for (i = 0; i < d->mux_cnt; i++)
+ if (d->chr_event[i])
+ d->chr_event[i](d->ext_opaque[i], event);
+}
+
+static void mux_chr_update_read_handler(CharDriverState *chr)
+{
+ MuxDriver *d = chr->opaque;
+
+ if (d->mux_cnt >= MAX_MUX) {
+ fprintf(stderr, "Cannot add I/O handlers, MUX array is full\n");
+ return;
+ }
+ d->ext_opaque[d->mux_cnt] = chr->handler_opaque;
+ d->chr_can_read[d->mux_cnt] = chr->chr_can_read;
+ d->chr_read[d->mux_cnt] = chr->chr_read;
+ d->chr_event[d->mux_cnt] = chr->chr_event;
+ /* Fix up the real driver with mux routines */
+ if (d->mux_cnt == 0) {
+ qemu_chr_add_handlers(d->drv, mux_chr_can_read, mux_chr_read,
+ mux_chr_event, chr);
+ }
+ chr->focus = d->mux_cnt;
+ d->mux_cnt++;
+}
+
+CharDriverState *qemu_chr_open_mux(CharDriverState *drv)
+{
CharDriverState *chr;
+ MuxDriver *d;
chr = qemu_mallocz(sizeof(CharDriverState));
if (!chr)
return NULL;
- chr->chr_write = null_chr_write;
- chr->chr_add_read_handler = null_chr_add_read_handler;
+ d = qemu_mallocz(sizeof(MuxDriver));
+ if (!d) {
+ free(chr);
+ return NULL;
+ }
+
+ chr->opaque = d;
+ d->drv = drv;
+ chr->focus = -1;
+ chr->chr_write = mux_chr_write;
+ chr->chr_update_read_handler = mux_chr_update_read_handler;
return chr;
}
+
#ifdef _WIN32
static void socket_cleanup(void)
@@ -1300,17 +1551,12 @@
typedef struct {
int fd_in, fd_out;
- IOCanRWHandler *fd_can_read;
- IOReadHandler *fd_read;
- void *fd_opaque;
int max_size;
} FDCharDriver;
-#define STDIO_MAX_CLIENTS 2
+#define STDIO_MAX_CLIENTS 1
+static int stdio_nb_clients = 0;
-static int stdio_nb_clients;
-static CharDriverState *stdio_clients[STDIO_MAX_CLIENTS];
-
static int fd_chr_write(CharDriverState *chr, const uint8_t *buf, int len)
{
FDCharDriver *s = chr->opaque;
@@ -1322,7 +1568,7 @@
CharDriverState *chr = opaque;
FDCharDriver *s = chr->opaque;
- s->max_size = s->fd_can_read(s->fd_opaque);
+ s->max_size = qemu_chr_can_read(chr);
return s->max_size;
}
@@ -1345,20 +1591,15 @@
return;
}
if (size > 0) {
- s->fd_read(s->fd_opaque, buf, size);
+ qemu_chr_read(chr, buf, size);
}
}
-static void fd_chr_add_read_handler(CharDriverState *chr,
- IOCanRWHandler *fd_can_read,
- IOReadHandler *fd_read, void *opaque)
+static void fd_chr_update_read_handler(CharDriverState *chr)
{
FDCharDriver *s = chr->opaque;
if (s->fd_in >= 0) {
- s->fd_can_read = fd_can_read;
- s->fd_read = fd_read;
- s->fd_opaque = opaque;
if (nographic && s->fd_in == 0) {
} else {
qemu_set_fd_handler2(s->fd_in, fd_chr_read_poll,
@@ -1385,7 +1626,7 @@
s->fd_out = fd_out;
chr->opaque = s;
chr->chr_write = fd_chr_write;
- chr->chr_add_read_handler = fd_chr_add_read_handler;
+ chr->chr_update_read_handler = fd_chr_update_read_handler;
qemu_chr_reset(chr);
@@ -1427,166 +1668,45 @@
/* for STDIO, we handle the case where several clients use it
(nographic mode) */
-#define TERM_ESCAPE 0x01 /* ctrl-a is used for escape */
-
#define TERM_FIFO_MAX_SIZE 1
-static int term_got_escape, client_index;
static uint8_t term_fifo[TERM_FIFO_MAX_SIZE];
static int term_fifo_size;
-static int term_timestamps;
-static int64_t term_timestamps_start;
-void term_print_help(void)
+static int stdio_read_poll(void *opaque)
{
- printf("\n"
- "C-a h print this help\n"
- "C-a x exit emulator\n"
- "C-a s save disk data back to file (if -snapshot)\n"
- "C-a b send break (magic sysrq)\n"
- "C-a t toggle console timestamps\n"
- "C-a c switch between console and monitor\n"
- "C-a C-a send C-a\n"
- );
-}
+ CharDriverState *chr = opaque;
-/* called when a char is received */
-static void stdio_received_byte(int ch)
-{
- if (term_got_escape) {
- term_got_escape = 0;
- switch(ch) {
- case 'h':
- term_print_help();
- break;
- case 'x':
- exit(0);
- break;
- case 's':
- {
- int i;
- for (i = 0; i < MAX_DISKS; i++) {
- if (bs_table[i])
- bdrv_commit(bs_table[i]);
- }
- }
- break;
- case 'b':
- if (client_index < stdio_nb_clients) {
- CharDriverState *chr;
- FDCharDriver *s;
-
- chr = stdio_clients[client_index];
- s = chr->opaque;
- chr->chr_event(s->fd_opaque, CHR_EVENT_BREAK);
- }
- break;
- case 'c':
- client_index++;
- if (client_index >= stdio_nb_clients)
- client_index = 0;
- if (client_index == 0) {
- /* send a new line in the monitor to get the prompt */
- ch = '\r';
- goto send_char;
- }
- break;
- case 't':
- term_timestamps = !term_timestamps;
- term_timestamps_start = -1;
- break;
- case TERM_ESCAPE:
- goto send_char;
- }
- } else if (ch == TERM_ESCAPE) {
- term_got_escape = 1;
- } else {
- send_char:
- if (client_index < stdio_nb_clients) {
- uint8_t buf[1];
- CharDriverState *chr;
- FDCharDriver *s;
-
- chr = stdio_clients[client_index];
- s = chr->opaque;
- if (s->fd_can_read(s->fd_opaque) > 0) {
- buf[0] = ch;
- s->fd_read(s->fd_opaque, buf, 1);
- } else if (term_fifo_size == 0) {
- term_fifo[term_fifo_size++] = ch;
- }
- }
+ /* try to flush the queue if needed */
+ if (term_fifo_size != 0 && qemu_chr_can_read(chr) > 0) {
+ qemu_chr_read(chr, term_fifo, 1);
+ term_fifo_size = 0;
}
-}
-
-static int stdio_read_poll(void *opaque)
-{
- CharDriverState *chr;
- FDCharDriver *s;
-
- if (client_index < stdio_nb_clients) {
- chr = stdio_clients[client_index];
- s = chr->opaque;
- /* try to flush the queue if needed */
- if (term_fifo_size != 0 && s->fd_can_read(s->fd_opaque) > 0) {
- s->fd_read(s->fd_opaque, term_fifo, 1);
- term_fifo_size = 0;
- }
- /* see if we can absorb more chars */
- if (term_fifo_size == 0)
- return 1;
- else
- return 0;
- } else {
+ /* see if we can absorb more chars */
+ if (term_fifo_size == 0)
return 1;
- }
+ else
+ return 0;
}
static void stdio_read(void *opaque)
{
int size;
uint8_t buf[1];
-
+ CharDriverState *chr = opaque;
+
size = read(0, buf, 1);
if (size == 0) {
/* stdin has been closed. Remove it from the active list. */
qemu_set_fd_handler2(0, NULL, NULL, NULL, NULL);
return;
}
- if (size > 0)
- stdio_received_byte(buf[0]);
-}
-
-static int stdio_write(CharDriverState *chr, const uint8_t *buf, int len)
-{
- FDCharDriver *s = chr->opaque;
- if (!term_timestamps) {
- return unix_write(s->fd_out, buf, len);
- } else {
- int i;
- char buf1[64];
-
- for(i = 0; i < len; i++) {
- unix_write(s->fd_out, buf + i, 1);
- if (buf[i] == '\n') {
- int64_t ti;
- int secs;
-
- ti = get_clock();
- if (term_timestamps_start == -1)
- term_timestamps_start = ti;
- ti -= term_timestamps_start;
- secs = ti / 1000000000;
- snprintf(buf1, sizeof(buf1),
- "[%02d:%02d:%02d.%03d] ",
- secs / 3600,
- (secs / 60) % 60,
- secs % 60,
- (int)((ti / 1000000) % 1000));
- unix_write(s->fd_out, buf1, strlen(buf1));
- }
+ if (size > 0) {
+ if (qemu_chr_can_read(chr) > 0) {
+ qemu_chr_read(chr, buf, 1);
+ } else if (term_fifo_size == 0) {
+ term_fifo[term_fifo_size++] = buf[0];
}
- return len;
}
}
@@ -1631,24 +1751,13 @@
{
CharDriverState *chr;
- if (nographic) {
- if (stdio_nb_clients >= STDIO_MAX_CLIENTS)
- return NULL;
- chr = qemu_chr_open_fd(0, 1);
- chr->chr_write = stdio_write;
- if (stdio_nb_clients == 0)
- qemu_set_fd_handler2(0, stdio_read_poll, stdio_read, NULL, NULL);
- client_index = stdio_nb_clients;
- } else {
- if (stdio_nb_clients != 0)
- return NULL;
- chr = qemu_chr_open_fd(0, 1);
- }
- stdio_clients[stdio_nb_clients++] = chr;
- if (stdio_nb_clients == 1) {
- /* set the terminal in raw mode */
- term_init();
- }
+ if (stdio_nb_clients >= STDIO_MAX_CLIENTS)
+ return NULL;
+ chr = qemu_chr_open_fd(0, 1);
+ qemu_set_fd_handler2(0, stdio_read_poll, stdio_read, NULL, chr);
+ stdio_nb_clients++;
+ term_init();
+
return chr;
}
@@ -1810,9 +1919,26 @@
return chr;
}
+typedef struct {
+ int fd;
+ int mode;
+} ParallelCharDriver;
+
+static int pp_hw_mode(ParallelCharDriver *s, uint16_t mode)
+{
+ if (s->mode != mode) {
+ int m = mode;
+ if (ioctl(s->fd, PPSETMODE, &m) < 0)
+ return 0;
+ s->mode = mode;
+ }
+ return 1;
+}
+
static int pp_ioctl(CharDriverState *chr, int cmd, void *arg)
{
- int fd = (int)chr->opaque;
+ ParallelCharDriver *drv = chr->opaque;
+ int fd = drv->fd;
uint8_t b;
switch(cmd) {
@@ -1829,7 +1955,10 @@
case CHR_IOCTL_PP_READ_CONTROL:
if (ioctl(fd, PPRCONTROL, &b) < 0)
return -ENOTSUP;
- *(uint8_t *)arg = b;
+ /* Linux gives only the lowest bits, and no way to know data
+ direction! For better compatibility set the fixed upper
+ bits. */
+ *(uint8_t *)arg = b | 0xc0;
break;
case CHR_IOCTL_PP_WRITE_CONTROL:
b = *(uint8_t *)arg;
@@ -1841,15 +1970,63 @@
return -ENOTSUP;
*(uint8_t *)arg = b;
break;
+ case CHR_IOCTL_PP_EPP_READ_ADDR:
+ if (pp_hw_mode(drv, IEEE1284_MODE_EPP|IEEE1284_ADDR)) {
+ struct ParallelIOArg *parg = arg;
+ int n = read(fd, parg->buffer, parg->count);
+ if (n != parg->count) {
+ return -EIO;
+ }
+ }
+ break;
+ case CHR_IOCTL_PP_EPP_READ:
+ if (pp_hw_mode(drv, IEEE1284_MODE_EPP)) {
+ struct ParallelIOArg *parg = arg;
+ int n = read(fd, parg->buffer, parg->count);
+ if (n != parg->count) {
+ return -EIO;
+ }
+ }
+ break;
+ case CHR_IOCTL_PP_EPP_WRITE_ADDR:
+ if (pp_hw_mode(drv, IEEE1284_MODE_EPP|IEEE1284_ADDR)) {
+ struct ParallelIOArg *parg = arg;
+ int n = write(fd, parg->buffer, parg->count);
+ if (n != parg->count) {
+ return -EIO;
+ }
+ }
+ break;
+ case CHR_IOCTL_PP_EPP_WRITE:
+ if (pp_hw_mode(drv, IEEE1284_MODE_EPP)) {
+ struct ParallelIOArg *parg = arg;
+ int n = write(fd, parg->buffer, parg->count);
+ if (n != parg->count) {
+ return -EIO;
+ }
+ }
+ break;
default:
return -ENOTSUP;
}
return 0;
}
+static void pp_close(CharDriverState *chr)
+{
+ ParallelCharDriver *drv = chr->opaque;
+ int fd = drv->fd;
+
+ pp_hw_mode(drv, IEEE1284_MODE_COMPAT);
+ ioctl(fd, PPRELEASE);
+ close(fd);
+ qemu_free(drv);
+}
+
static CharDriverState *qemu_chr_open_pp(const char *filename)
{
CharDriverState *chr;
+ ParallelCharDriver *drv;
int fd;
fd = open(filename, O_RDWR);
@@ -1861,15 +2038,24 @@
return NULL;
}
+ drv = qemu_mallocz(sizeof(ParallelCharDriver));
+ if (!drv) {
+ close(fd);
+ return NULL;
+ }
+ drv->fd = fd;
+ drv->mode = IEEE1284_MODE_COMPAT;
+
chr = qemu_mallocz(sizeof(CharDriverState));
if (!chr) {
+ qemu_free(drv);
close(fd);
return NULL;
}
- chr->opaque = (void *)fd;
chr->chr_write = null_chr_write;
- chr->chr_add_read_handler = null_chr_add_read_handler;
chr->chr_ioctl = pp_ioctl;
+ chr->chr_close = pp_close;
+ chr->opaque = drv;
qemu_chr_reset(chr);
@@ -1887,9 +2073,6 @@
#ifdef _WIN32
typedef struct {
- IOCanRWHandler *fd_can_read;
- IOReadHandler *fd_read;
- void *win_opaque;
int max_size;
HANDLE hcom, hrecv, hsend;
OVERLAPPED orecv, osend;
@@ -1905,8 +2088,10 @@
static int win_chr_poll(void *opaque);
static int win_chr_pipe_poll(void *opaque);
-static void win_chr_close2(WinCharState *s)
+static void win_chr_close(CharDriverState *chr)
{
+ WinCharState *s = chr->opaque;
+
if (s->hsend) {
CloseHandle(s->hsend);
s->hsend = NULL;
@@ -1920,19 +2105,14 @@
s->hcom = NULL;
}
if (s->fpipe)
- qemu_del_polling_cb(win_chr_pipe_poll, s);
+ qemu_del_polling_cb(win_chr_pipe_poll, chr);
else
- qemu_del_polling_cb(win_chr_poll, s);
+ qemu_del_polling_cb(win_chr_poll, chr);
}
-static void win_chr_close(CharDriverState *chr)
+static int win_chr_init(CharDriverState *chr, const char *filename)
{
WinCharState *s = chr->opaque;
- win_chr_close2(s);
-}
-
-static int win_chr_init(WinCharState *s, const char *filename)
-{
COMMCONFIG comcfg;
COMMTIMEOUTS cto = { 0, 0, 0, 0, 0};
COMSTAT comstat;
@@ -1989,11 +2169,11 @@
fprintf(stderr, "Failed ClearCommError\n");
goto fail;
}
- qemu_add_polling_cb(win_chr_poll, s);
+ qemu_add_polling_cb(win_chr_poll, chr);
return 0;
fail:
- win_chr_close2(s);
+ win_chr_close(chr);
return -1;
}
@@ -2031,14 +2211,17 @@
return len1 - len;
}
-static int win_chr_read_poll(WinCharState *s)
+static int win_chr_read_poll(CharDriverState *chr)
{
- s->max_size = s->fd_can_read(s->win_opaque);
+ WinCharState *s = chr->opaque;
+
+ s->max_size = qemu_chr_can_read(chr);
return s->max_size;
}
-
-static void win_chr_readfile(WinCharState *s)
+
+static void win_chr_readfile(CharDriverState *chr)
{
+ WinCharState *s = chr->opaque;
int ret, err;
uint8_t buf[1024];
DWORD size;
@@ -2054,47 +2237,39 @@
}
if (size > 0) {
- s->fd_read(s->win_opaque, buf, size);
+ qemu_chr_read(chr, buf, size);
}
}
-static void win_chr_read(WinCharState *s)
+static void win_chr_read(CharDriverState *chr)
{
+ WinCharState *s = chr->opaque;
+
if (s->len > s->max_size)
s->len = s->max_size;
if (s->len == 0)
return;
- win_chr_readfile(s);
+ win_chr_readfile(chr);
}
static int win_chr_poll(void *opaque)
{
- WinCharState *s = opaque;
+ CharDriverState *chr = opaque;
+ WinCharState *s = chr->opaque;
COMSTAT status;
DWORD comerr;
ClearCommError(s->hcom, &comerr, &status);
if (status.cbInQue > 0) {
s->len = status.cbInQue;
- win_chr_read_poll(s);
- win_chr_read(s);
+ win_chr_read_poll(chr);
+ win_chr_read(chr);
return 1;
}
return 0;
}
-static void win_chr_add_read_handler(CharDriverState *chr,
- IOCanRWHandler *fd_can_read,
- IOReadHandler *fd_read, void *opaque)
-{
- WinCharState *s = chr->opaque;
-
- s->fd_can_read = fd_can_read;
- s->fd_read = fd_read;
- s->win_opaque = opaque;
-}
-
static CharDriverState *qemu_chr_open_win(const char *filename)
{
CharDriverState *chr;
@@ -2110,10 +2285,9 @@
}
chr->opaque = s;
chr->chr_write = win_chr_write;
- chr->chr_add_read_handler = win_chr_add_read_handler;
chr->chr_close = win_chr_close;
- if (win_chr_init(s, filename) < 0) {
+ if (win_chr_init(chr, filename) < 0) {
free(s);
free(chr);
return NULL;
@@ -2124,21 +2298,23 @@
static int win_chr_pipe_poll(void *opaque)
{
- WinCharState *s = opaque;
+ CharDriverState *chr = opaque;
+ WinCharState *s = chr->opaque;
DWORD size;
PeekNamedPipe(s->hcom, NULL, 0, NULL, &size, NULL);
if (size > 0) {
s->len = size;
- win_chr_read_poll(s);
- win_chr_read(s);
+ win_chr_read_poll(chr);
+ win_chr_read(chr);
return 1;
}
return 0;
}
-static int win_chr_pipe_init(WinCharState *s, const char *filename)
+static int win_chr_pipe_init(CharDriverState *chr, const char *filename)
{
+ WinCharState *s = chr->opaque;
OVERLAPPED ov;
int ret;
DWORD size;
@@ -2190,11 +2366,11 @@
CloseHandle(ov.hEvent);
ov.hEvent = NULL;
}
- qemu_add_polling_cb(win_chr_pipe_poll, s);
+ qemu_add_polling_cb(win_chr_pipe_poll, chr);
return 0;
fail:
- win_chr_close2(s);
+ win_chr_close(chr);
return -1;
}
@@ -2214,10 +2390,9 @@
}
chr->opaque = s;
chr->chr_write = win_chr_write;
- chr->chr_add_read_handler = win_chr_add_read_handler;
chr->chr_close = win_chr_close;
- if (win_chr_pipe_init(s, filename) < 0) {
+ if (win_chr_pipe_init(chr, filename) < 0) {
free(s);
free(chr);
return NULL;
@@ -2242,7 +2417,6 @@
s->hcom = fd_out;
chr->opaque = s;
chr->chr_write = win_chr_write;
- chr->chr_add_read_handler = win_chr_add_read_handler;
qemu_chr_reset(chr);
return chr;
}
@@ -2264,9 +2438,6 @@
/* UDP Net console */
typedef struct {
- IOCanRWHandler *fd_can_read;
- IOReadHandler *fd_read;
- void *fd_opaque;
int fd;
struct sockaddr_in daddr;
char buf[1024];
@@ -2288,15 +2459,15 @@
CharDriverState *chr = opaque;
NetCharDriver *s = chr->opaque;
- s->max_size = s->fd_can_read(s->fd_opaque);
+ s->max_size = qemu_chr_can_read(chr);
/* If there were any stray characters in the queue process them
* first
*/
while (s->max_size > 0 && s->bufptr < s->bufcnt) {
- s->fd_read(s->fd_opaque, &s->buf[s->bufptr], 1);
+ qemu_chr_read(chr, &s->buf[s->bufptr], 1);
s->bufptr++;
- s->max_size = s->fd_can_read(s->fd_opaque);
+ s->max_size = qemu_chr_can_read(chr);
}
return s->max_size;
}
@@ -2315,22 +2486,17 @@
s->bufptr = 0;
while (s->max_size > 0 && s->bufptr < s->bufcnt) {
- s->fd_read(s->fd_opaque, &s->buf[s->bufptr], 1);
+ qemu_chr_read(chr, &s->buf[s->bufptr], 1);
s->bufptr++;
- s->max_size = s->fd_can_read(s->fd_opaque);
+ s->max_size = qemu_chr_can_read(chr);
}
}
-static void udp_chr_add_read_handler(CharDriverState *chr,
- IOCanRWHandler *fd_can_read,
- IOReadHandler *fd_read, void *opaque)
+static void udp_chr_update_read_handler(CharDriverState *chr)
{
NetCharDriver *s = chr->opaque;
if (s->fd >= 0) {
- s->fd_can_read = fd_can_read;
- s->fd_read = fd_read;
- s->fd_opaque = opaque;
qemu_set_fd_handler2(s->fd, udp_chr_read_poll,
udp_chr_read, NULL, chr);
}
@@ -2380,7 +2546,7 @@
s->bufptr = 0;
chr->opaque = s;
chr->chr_write = udp_chr_write;
- chr->chr_add_read_handler = udp_chr_add_read_handler;
+ chr->chr_update_read_handler = udp_chr_update_read_handler;
return chr;
return_err:
@@ -2397,13 +2563,11 @@
/* TCP Net console */
typedef struct {
- IOCanRWHandler *fd_can_read;
- IOReadHandler *fd_read;
- void *fd_opaque;
int fd, listen_fd;
int connected;
int max_size;
int do_telnetopt;
+ int do_nodelay;
int is_unix;
} TCPCharDriver;
@@ -2426,9 +2590,7 @@
TCPCharDriver *s = chr->opaque;
if (!s->connected)
return 0;
- if (!s->fd_can_read)
- return 0;
- s->max_size = s->fd_can_read(s->fd_opaque);
+ s->max_size = qemu_chr_can_read(chr);
return s->max_size;
}
@@ -2461,7 +2623,7 @@
} else {
if ((unsigned char)buf[i] == IAC_BREAK && s->do_telnetopt == 2) {
/* Handle IAC break commands by sending a serial break */
- chr->chr_event(s->fd_opaque, CHR_EVENT_BREAK);
+ qemu_chr_event(chr, CHR_EVENT_BREAK);
s->do_telnetopt++;
}
s->do_telnetopt++;
@@ -2508,21 +2670,10 @@
if (s->do_telnetopt)
tcp_chr_process_IAC_bytes(chr, s, buf, &size);
if (size > 0)
- s->fd_read(s->fd_opaque, buf, size);
+ qemu_chr_read(chr, buf, size);
}
}
-static void tcp_chr_add_read_handler(CharDriverState *chr,
- IOCanRWHandler *fd_can_read,
- IOReadHandler *fd_read, void *opaque)
-{
- TCPCharDriver *s = chr->opaque;
-
- s->fd_can_read = fd_can_read;
- s->fd_read = fd_read;
- s->fd_opaque = opaque;
-}
-
static void tcp_chr_connect(void *opaque)
{
CharDriverState *chr = opaque;
@@ -2549,6 +2700,12 @@
send(fd, (char *)buf, 3, 0);
}
+static void socket_set_nodelay(int fd)
+{
+ int val = 1;
+ setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
+}
+
static void tcp_chr_accept(void *opaque)
{
CharDriverState *chr = opaque;
@@ -2582,6 +2739,8 @@
}
}
socket_set_nonblock(fd);
+ if (s->do_nodelay)
+ socket_set_nodelay(fd);
s->fd = fd;
qemu_set_fd_handler(s->listen_fd, NULL, NULL, NULL);
tcp_chr_connect(chr);
@@ -2606,6 +2765,7 @@
int fd = -1, ret, err, val;
int is_listen = 0;
int is_waitconnect = 1;
+ int do_nodelay = 0;
const char *ptr;
struct sockaddr_in saddr;
#ifndef _WIN32
@@ -2636,6 +2796,8 @@
is_listen = 1;
} else if (!strncmp(ptr,"nowait",6)) {
is_waitconnect = 0;
+ } else if (!strncmp(ptr,"nodelay",6)) {
+ do_nodelay = 1;
} else {
printf("Unknown option: %s\n", ptr);
goto fail;
@@ -2668,10 +2830,10 @@
s->fd = -1;
s->listen_fd = -1;
s->is_unix = is_unix;
+ s->do_nodelay = do_nodelay && !is_unix;
chr->opaque = s;
chr->chr_write = tcp_chr_write;
- chr->chr_add_read_handler = tcp_chr_add_read_handler;
chr->chr_close = tcp_chr_close;
if (is_listen) {
@@ -2709,6 +2871,10 @@
if (err == EINTR || err == EWOULDBLOCK) {
} else if (err == EINPROGRESS) {
break;
+#ifdef _WIN32
+ } else if (err == WSAEALREADY) {
+ break;
+#endif
} else {
goto fail;
}
@@ -2718,6 +2884,7 @@
}
}
s->fd = fd;
+ socket_set_nodelay(fd);
if (s->connected)
tcp_chr_connect(chr);
else
@@ -2757,6 +2924,16 @@
if (strstart(filename, "udp:", &p)) {
return qemu_chr_open_udp(p);
} else
+ if (strstart(filename, "mon:", &p)) {
+ CharDriverState *drv = qemu_chr_open(p);
+ if (drv) {
+ drv = qemu_chr_open_mux(drv);
+ monitor_init(drv, !nographic);
+ return drv;
+ }
+ printf("Unable to open driver: %s\n", p);
+ return 0;
+ } else
#ifndef _WIN32
if (strstart(filename, "unix:", &p)) {
return qemu_chr_open_tcp(p, 0, 1);
@@ -3235,7 +3412,15 @@
uint8_t buf[4096];
int size;
+#ifdef __sun__
+ struct strbuf sbuf;
+ int f = 0;
+ sbuf.maxlen = sizeof(buf);
+ sbuf.buf = buf;
+ size = getmsg(s->fd, NULL, &sbuf, &f) >=0 ? sbuf.len : -1;
+#else
size = read(s->fd, buf, sizeof(buf));
+#endif
if (size > 0) {
qemu_send_packet(s->vc, buf, size);
}
@@ -3278,10 +3463,135 @@
return fd;
}
#elif defined(__sun__)
+#define TUNNEWPPA (('T'<<16) | 0x0001)
+/*
+ * Allocate TAP device, returns opened fd.
+ * Stores dev name in the first arg(must be large enough).
+ */
+int tap_alloc(char *dev)
+{
+ int tap_fd, if_fd, ppa = -1;
+ static int ip_fd = 0;
+ char *ptr;
+
+ static int arp_fd = 0;
+ int ip_muxid, arp_muxid;
+ struct strioctl strioc_if, strioc_ppa;
+ int link_type = I_PLINK;;
+ struct lifreq ifr;
+ char actual_name[32] = "";
+
+ memset(&ifr, 0x0, sizeof(ifr));
+
+ if( *dev ){
+ ptr = dev;
+ while( *ptr && !isdigit((int)*ptr) ) ptr++;
+ ppa = atoi(ptr);
+ }
+
+ /* Check if IP device was opened */
+ if( ip_fd )
+ close(ip_fd);
+
+ if( (ip_fd = open("/dev/udp", O_RDWR, 0)) < 0){
+ syslog(LOG_ERR, "Can't open /dev/ip (actually /dev/udp)");
+ return -1;
+ }
+
+ if( (tap_fd = open("/dev/tap", O_RDWR, 0)) < 0){
+ syslog(LOG_ERR, "Can't open /dev/tap");
+ return -1;
+ }
+
+ /* Assign a new PPA and get its unit number. */
+ strioc_ppa.ic_cmd = TUNNEWPPA;
+ strioc_ppa.ic_timout = 0;
+ strioc_ppa.ic_len = sizeof(ppa);
+ strioc_ppa.ic_dp = (char *)&ppa;
+ if ((ppa = ioctl (tap_fd, I_STR, &strioc_ppa)) < 0)
+ syslog (LOG_ERR, "Can't assign new interface");
+
+ if( (if_fd = open("/dev/tap", O_RDWR, 0)) < 0){
+ syslog(LOG_ERR, "Can't open /dev/tap (2)");
+ return -1;
+ }
+ if(ioctl(if_fd, I_PUSH, "ip") < 0){
+ syslog(LOG_ERR, "Can't push IP module");
+ return -1;
+ }
+
+ if (ioctl(if_fd, SIOCGLIFFLAGS, &ifr) < 0)
+ syslog(LOG_ERR, "Can't get flags\n");
+
+ snprintf (actual_name, 32, "tap%d", ppa);
+ strncpy (ifr.lifr_name, actual_name, sizeof (ifr.lifr_name));
+
+ ifr.lifr_ppa = ppa;
+ /* Assign ppa according to the unit number returned by tun device */
+
+ if (ioctl (if_fd, SIOCSLIFNAME, &ifr) < 0)
+ syslog (LOG_ERR, "Can't set PPA %d", ppa);
+ if (ioctl(if_fd, SIOCGLIFFLAGS, &ifr) <0)
+ syslog (LOG_ERR, "Can't get flags\n");
+ /* Push arp module to if_fd */
+ if (ioctl (if_fd, I_PUSH, "arp") < 0)
+ syslog (LOG_ERR, "Can't push ARP module (2)");
+
+ /* Push arp module to ip_fd */
+ if (ioctl (ip_fd, I_POP, NULL) < 0)
+ syslog (LOG_ERR, "I_POP failed\n");
+ if (ioctl (ip_fd, I_PUSH, "arp") < 0)
+ syslog (LOG_ERR, "Can't push ARP module (3)\n");
+ /* Open arp_fd */
+ if ((arp_fd = open ("/dev/tap", O_RDWR, 0)) < 0)
+ syslog (LOG_ERR, "Can't open %s\n", "/dev/tap");
+
+ /* Set ifname to arp */
+ strioc_if.ic_cmd = SIOCSLIFNAME;
+ strioc_if.ic_timout = 0;
+ strioc_if.ic_len = sizeof(ifr);
+ strioc_if.ic_dp = (char *)𝔦
+ if (ioctl(arp_fd, I_STR, &strioc_if) < 0){
+ syslog (LOG_ERR, "Can't set ifname to arp\n");
+ }
+
+ if((ip_muxid = ioctl(ip_fd, I_LINK, if_fd)) < 0){
+ syslog(LOG_ERR, "Can't link TAP device to IP");
+ return -1;
+ }
+
+ if ((arp_muxid = ioctl (ip_fd, link_type, arp_fd)) < 0)
+ syslog (LOG_ERR, "Can't link TAP device to ARP");
+
+ close (if_fd);
+
+ memset(&ifr, 0x0, sizeof(ifr));
+ strncpy (ifr.lifr_name, actual_name, sizeof (ifr.lifr_name));
+ ifr.lifr_ip_muxid = ip_muxid;
+ ifr.lifr_arp_muxid = arp_muxid;
+
+ if (ioctl (ip_fd, SIOCSLIFMUXID, &ifr) < 0)
+ {
+ ioctl (ip_fd, I_PUNLINK , arp_muxid);
+ ioctl (ip_fd, I_PUNLINK, ip_muxid);
+ syslog (LOG_ERR, "Can't set multiplexor id");
+ }
+
+ sprintf(dev, "tap%d", ppa);
+ return tap_fd;
+}
+
static int tap_open(char *ifname, int ifname_size)
{
- fprintf(stderr, "warning: tap_open not yet implemented\n");
- return -1;
+ char dev[10]="";
+ int fd;
+ if( (fd = tap_alloc(dev)) < 0 ){
+ fprintf(stderr, "Cannot allocate TAP device\n");
+ return -1;
+ }
+ pstrcpy(ifname, ifname_size, dev);
+ fcntl(fd, F_SETFL, O_NONBLOCK);
+ return fd;
}
#else
static int tap_open(char *ifname, int ifname_size)
@@ -3329,13 +3639,21 @@
if (fd < 0)
return -1;
- if (!setup_script)
+ if (!setup_script || !strcmp(setup_script, "no"))
setup_script = "";
if (setup_script[0] != '\0') {
/* try to launch network init script */
pid = fork();
if (pid >= 0) {
if (pid == 0) {
+ int open_max = sysconf (_SC_OPEN_MAX), i;
+ for (i = 0; i < open_max; i++)
+ if (i != STDIN_FILENO &&
+ i != STDOUT_FILENO &&
+ i != STDERR_FILENO &&
+ i != fd)
+ close(i);
+
parg = args;
*parg++ = (char *)setup_script;
*parg++ = ifname;
@@ -3617,7 +3935,7 @@
int so_type=-1, optlen=sizeof(so_type);
if(getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&so_type, &optlen)< 0) {
- fprintf(stderr, "qemu: error: setsockopt(SO_TYPE) for fd=%d failed\n", fd);
+ fprintf(stderr, "qemu: error: getsockopt(SO_TYPE) for fd=%d failed\n", fd);
return NULL;
}
switch(so_type) {
@@ -3724,6 +4042,10 @@
if (err == EINTR || err == EWOULDBLOCK) {
} else if (err == EINPROGRESS) {
break;
+#ifdef _WIN32
+ } else if (err == WSAEALREADY) {
+ break;
+#endif
} else {
perror("connect");
closesocket(fd);
@@ -3901,7 +4223,9 @@
if (net_tap_fd_init(vlan, fd))
ret = 0;
} else {
- get_param_value(ifname, sizeof(ifname), "ifname", p);
+ if (get_param_value(ifname, sizeof(ifname), "ifname", p) <= 0) {
+ ifname[0] = '\0';
+ }
if (get_param_value(setup_script, sizeof(setup_script), "script", p) == 0) {
pstrcpy(setup_script, sizeof(setup_script), DEFAULT_NETWORK_SCRIPT);
}
@@ -3998,8 +4322,8 @@
dev = usb_msd_init(p);
} else if (strstart(devname, "net:", &p)) {
unsigned int nr = strtoul(p, NULL, 0);
- if (nr >= (unsigned int)nb_nics || strcmp(nd_table[nr].model, "usb"))
- return -1;
+ if (nr >= (unsigned int) nb_nics || strcmp(nd_table[nr].model, "usb"))
+ return -1;
dev = usb_net_init(&nd_table[nr]);
} else if (strstart(devname, "gadget", &p)) {
dev = usb_gadget;
@@ -4012,7 +4336,7 @@
return -1;
goto attach;
} else {
- return 0;
+ return -1;
}
if (!dev)
return -1;
@@ -4355,51 +4679,11 @@
for (iter = pcmcia_sockets; iter; iter = iter->next)
term_printf("%s: %s\n", iter->socket->slot_string,
- iter->socket->attached ? iter->socket->card_string :
- "Empty");
+ iter->socket->attached ? iter->socket->card_string :
+ "Empty");
}
/***********************************************************/
-/* pid file */
-
-static char *pid_filename;
-
-/* Remove PID file. Called on normal exit */
-
-static void remove_pidfile(void)
-{
- unlink (pid_filename);
-}
-
-static void create_pidfile(const char *filename)
-{
- struct stat pidstat;
- FILE *f;
-
- /* Try to write our PID to the named file */
- if (stat(filename, &pidstat) < 0) {
- if (errno == ENOENT) {
- if ((f = fopen (filename, "w")) == NULL) {
- perror("Opening pidfile");
- exit(1);
- }
- fprintf(f, "%d\n", getpid());
- fclose(f);
- pid_filename = qemu_strdup(filename);
- if (!pid_filename) {
- fprintf(stderr, "Could not save PID filename");
- exit(1);
- }
- atexit(remove_pidfile);
- }
- } else {
- fprintf(stderr, "%s already exists. Remove it and try again.\n",
- filename);
- exit(1);
- }
-}
-
-/***********************************************************/
/* dumb display */
static void dumb_update(DisplayState *ds, int x, int y, int w, int h)
@@ -4435,6 +4719,7 @@
IOCanRWHandler *fd_read_poll;
IOHandler *fd_read;
IOHandler *fd_write;
+ int deleted;
void *opaque;
/* temporary data */
struct pollfd *ufd;
@@ -4460,8 +4745,7 @@
if (ioh == NULL)
break;
if (ioh->fd == fd) {
- *pioh = ioh->next;
- qemu_free(ioh);
+ ioh->deleted = 1;
break;
}
pioh = &ioh->next;
@@ -4482,6 +4766,7 @@
ioh->fd_read = fd_read;
ioh->fd_write = fd_write;
ioh->opaque = opaque;
+ ioh->deleted = 0;
}
return 0;
}
@@ -6130,9 +6415,12 @@
void main_loop_wait(int timeout)
{
- IOHandlerRecord *ioh, *ioh_next;
+ IOHandlerRecord *ioh;
fd_set rfds, wfds, xfds;
int ret, nfds;
+#ifdef _WIN32
+ int ret2, i;
+#endif
struct timeval tv;
PollingEntry *pe;
@@ -6143,7 +6431,7 @@
ret |= pe->func(pe->opaque);
}
#ifdef _WIN32
- if (ret == 0 && timeout > 0) {
+ if (ret == 0) {
int err;
WaitObjects *w = &wait_objects;
@@ -6151,10 +6439,25 @@
if (WAIT_OBJECT_0 + 0 <= ret && ret <= WAIT_OBJECT_0 + w->num - 1) {
if (w->func[ret - WAIT_OBJECT_0])
w->func[ret - WAIT_OBJECT_0](w->opaque[ret - WAIT_OBJECT_0]);
+
+ /* Check for additional signaled events */
+ for(i = (ret - WAIT_OBJECT_0 + 1); i < w->num; i++) {
+
+ /* Check if event is signaled */
+ ret2 = WaitForSingleObject(w->events[i], 0);
+ if(ret2 == WAIT_OBJECT_0) {
+ if (w->func[i])
+ w->func[i](w->opaque[i]);
+ } else if (ret2 == WAIT_TIMEOUT) {
+ } else {
+ err = GetLastError();
+ fprintf(stderr, "WaitForSingleObject error %d %d\n", i, err);
+ }
+ }
} else if (ret == WAIT_TIMEOUT) {
} else {
err = GetLastError();
- fprintf(stderr, "Wait error %d %d\n", ret, err);
+ fprintf(stderr, "WaitForMultipleObjects error %d %d\n", ret, err);
}
}
#endif
@@ -6165,6 +6468,8 @@
FD_ZERO(&wfds);
FD_ZERO(&xfds);
for(ioh = first_io_handler; ioh != NULL; ioh = ioh->next) {
+ if (ioh->deleted)
+ continue;
if (ioh->fd_read &&
(!ioh->fd_read_poll ||
ioh->fd_read_poll(ioh->opaque) != 0)) {
@@ -6192,9 +6497,11 @@
#endif
ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv);
if (ret > 0) {
- /* XXX: better handling of removal */
- for(ioh = first_io_handler; ioh != NULL; ioh = ioh_next) {
- ioh_next = ioh->next;
+ IOHandlerRecord **pioh;
+
+ for(ioh = first_io_handler; ioh != NULL; ioh = ioh->next) {
+ if (ioh->deleted)
+ continue;
if (FD_ISSET(ioh->fd, &rfds)) {
ioh->fd_read(ioh->opaque);
}
@@ -6202,6 +6509,17 @@
ioh->fd_write(ioh->opaque);
}
}
+
+ /* remove deleted IO handlers */
+ pioh = &first_io_handler;
+ while (*pioh) {
+ ioh = *pioh;
+ if (ioh->deleted) {
+ *pioh = ioh->next;
+ qemu_free(ioh);
+ } else
+ pioh = &ioh->next;
+ }
}
#if defined(CONFIG_SLIRP)
if (slirp_inited) {
@@ -6255,13 +6573,16 @@
#ifdef CONFIG_PROFILER
qemu_time += profile_getclock() - ti;
#endif
+ if (ret == EXCP_HLT) {
+ /* Give the next CPU a chance to run. */
+ cur_cpu = env;
+ continue;
+ }
if (ret != EXCP_HALTED)
break;
/* all CPUs are halted ? */
- if (env == cur_cpu) {
- ret = EXCP_HLT;
+ if (env == cur_cpu)
break;
- }
}
cur_cpu = env;
@@ -6282,9 +6603,9 @@
if (ret == EXCP_DEBUG) {
vm_stop(EXCP_DEBUG);
}
- /* if hlt instruction, we wait until the next IRQ */
+ /* If all cpus are halted then wait until the next IRQ */
/* XXX: use timeout computed from timers */
- if (ret == EXCP_HLT)
+ if (ret == EXCP_HALTED)
timeout = 10;
else
timeout = 0;
@@ -6305,22 +6626,25 @@
void help(void)
{
- printf("QEMU PC emulator version " QEMU_VERSION ", Copyright (c) 2003-2006 Fabrice Bellard\n"
+ printf("QEMU PC emulator version " QEMU_VERSION ", Copyright (c) 2003-2007 Fabrice Bellard\n"
"usage: %s [options] [disk_image]\n"
"\n"
"'disk_image' is a raw hard image image for IDE hard disk 0\n"
"\n"
"Standard options:\n"
"-M machine select emulated machine (-M ? for list)\n"
+ "-cpu cpu select CPU (-cpu ? for list)\n"
"-fda/-fdb file use 'file' as floppy disk 0/1 image\n"
"-hda/-hdb file use 'file' as IDE hard disk 0/1 image\n"
"-hdc/-hdd file use 'file' as IDE hard disk 2/3 image\n"
"-cdrom file use 'file' as IDE cdrom image (cdrom is ide1 master)\n"
"-mtdblock file use 'file' as on-board Flash memory image\n"
"-sd file use 'file' as SecureDigital card image\n"
+ "-pflash file use 'file' as a parallel flash image\n"
"-boot [a|c|d|n] boot on floppy (a), hard disk (c), CD-ROM (d), or network (n)\n"
"-snapshot write to temporary files instead of disk image files\n"
#ifdef CONFIG_SDL
+ "-no-frame open SDL window without a frame and window decorations\n"
"-no-quit disable SDL window close capability\n"
#endif
#ifdef TARGET_I386
@@ -6329,7 +6653,7 @@
"-m megs set virtual RAM size to megs MB [default=%d]\n"
"-smp n set the number of CPUs to 'n' [default=1]\n"
"-nographic disable graphical output and redirect serial I/Os to console\n"
- "-vertical rotate graphical output left (only PXA targets)\n"
+ "-portrait rotate graphical output 90 deg left (only PXA LCD)\n"
#ifndef _WIN32
"-k language use keyboard layout (for example \"fr\" for French)\n"
#endif
@@ -6351,6 +6675,7 @@
#if defined(TARGET_PPC) || defined(TARGET_SPARC)
"-g WxH[xDEPTH] Set the initial graphical resolution and depth\n"
#endif
+ "-name string set the name of the guest\n"
"\n"
"Network options:\n"
"-net nic[,vlan=n][,macaddr=addr][,model=type]\n"
@@ -6367,6 +6692,7 @@
"-net tap[,vlan=n][,fd=h][,ifname=name][,script=file]\n"
" connect the host TAP network interface to VLAN 'n' and use\n"
" the network script 'file' (default=%s);\n"
+ " use 'script=no' to disable script execution;\n"
" use 'fd=h' to connect to an already opened TAP interface\n"
#endif
"-net socket[,vlan=n][,fd=h][,listen=[host]:port][,connect=host:port]\n"
@@ -6377,7 +6703,8 @@
" is provided, the default is '-net nic -net user'\n"
"\n"
#ifdef CONFIG_SLIRP
- "-tftp prefix allow tftp access to files starting with prefix [-net user]\n"
+ "-tftp dir allow tftp access to files in dir [-net user]\n"
+ "-bootp file advertise file in BOOTP replies\n"
#ifndef _WIN32
"-smb dir allow SMB access to files in 'dir' [-net user]\n"
#endif
@@ -6396,8 +6723,8 @@
"-parallel dev redirect the parallel port to char device 'dev'\n"
"-pidfile file Write PID to 'file'\n"
"-S freeze CPU at startup (use 'c' to start execution)\n"
- "-s wait gdb connection to port %d\n"
- "-p port change gdb connection port\n"
+ "-s wait gdb connection to port\n"
+ "-p port set gdb connection port [default=%s]\n"
"-d item1,... output log to %s (use -d ? for a list of log items)\n"
"-hdachs c,h,s[,t] force hard disk 0 physical geometry and the optional BIOS\n"
" translation (t=none or lba) (usually qemu can guess them)\n"
@@ -6421,6 +6748,9 @@
"-daemonize daemonize QEMU after initializing\n"
#endif
"-option-rom rom load a file, rom, into the option ROM space\n"
+#ifdef TARGET_SPARC
+ "-prom-env variable=value set OpenBIOS nvram variables\n"
+#endif
"\n"
"During emulation, the following keys are useful:\n"
"ctrl-alt-f toggle full screen\n"
@@ -6445,6 +6775,7 @@
QEMU_OPTION_h,
QEMU_OPTION_M,
+ QEMU_OPTION_cpu,
QEMU_OPTION_fda,
QEMU_OPTION_fdb,
QEMU_OPTION_hda,
@@ -6454,6 +6785,7 @@
QEMU_OPTION_cdrom,
QEMU_OPTION_mtdblock,
QEMU_OPTION_sd,
+ QEMU_OPTION_pflash,
QEMU_OPTION_boot,
QEMU_OPTION_snapshot,
#ifdef TARGET_I386
@@ -6461,7 +6793,7 @@
#endif
QEMU_OPTION_m,
QEMU_OPTION_nographic,
- QEMU_OPTION_vertical,
+ QEMU_OPTION_portrait,
#ifdef HAS_AUDIO
QEMU_OPTION_audio_help,
QEMU_OPTION_soundhw,
@@ -6469,6 +6801,7 @@
QEMU_OPTION_net,
QEMU_OPTION_tftp,
+ QEMU_OPTION_bootp,
QEMU_OPTION_smb,
QEMU_OPTION_redir,
@@ -6486,13 +6819,16 @@
QEMU_OPTION_k,
QEMU_OPTION_localtime,
QEMU_OPTION_cirrusvga,
+ QEMU_OPTION_vmsvga,
QEMU_OPTION_g,
QEMU_OPTION_std_vga,
+ QEMU_OPTION_echr,
QEMU_OPTION_monitor,
QEMU_OPTION_serial,
QEMU_OPTION_parallel,
QEMU_OPTION_loadvm,
QEMU_OPTION_full_screen,
+ QEMU_OPTION_no_frame,
QEMU_OPTION_no_quit,
QEMU_OPTION_pidfile,
QEMU_OPTION_no_kqemu,
@@ -6508,6 +6844,9 @@
QEMU_OPTION_show_cursor,
QEMU_OPTION_daemonize,
QEMU_OPTION_option_rom,
+ QEMU_OPTION_semihosting,
+ QEMU_OPTION_name,
+ QEMU_OPTION_prom_env,
};
typedef struct QEMUOption {
@@ -6518,8 +6857,10 @@
const QEMUOption qemu_options[] = {
{ "h", 0, QEMU_OPTION_h },
+ { "help", 0, QEMU_OPTION_h },
{ "M", HAS_ARG, QEMU_OPTION_M },
+ { "cpu", HAS_ARG, QEMU_OPTION_cpu },
{ "fda", HAS_ARG, QEMU_OPTION_fda },
{ "fdb", HAS_ARG, QEMU_OPTION_fdb },
{ "hda", HAS_ARG, QEMU_OPTION_hda },
@@ -6529,6 +6870,7 @@
{ "cdrom", HAS_ARG, QEMU_OPTION_cdrom },
{ "mtdblock", HAS_ARG, QEMU_OPTION_mtdblock },
{ "sd", HAS_ARG, QEMU_OPTION_sd },
+ { "pflash", HAS_ARG, QEMU_OPTION_pflash },
{ "boot", HAS_ARG, QEMU_OPTION_boot },
{ "snapshot", 0, QEMU_OPTION_snapshot },
#ifdef TARGET_I386
@@ -6536,7 +6878,7 @@
#endif
{ "m", HAS_ARG, QEMU_OPTION_m },
{ "nographic", 0, QEMU_OPTION_nographic },
- { "vertical", 0, QEMU_OPTION_vertical },
+ { "portrait", 0, QEMU_OPTION_portrait },
{ "k", HAS_ARG, QEMU_OPTION_k },
#ifdef HAS_AUDIO
{ "audio-help", 0, QEMU_OPTION_audio_help },
@@ -6546,6 +6888,7 @@
{ "net", HAS_ARG, QEMU_OPTION_net},
#ifdef CONFIG_SLIRP
{ "tftp", HAS_ARG, QEMU_OPTION_tftp },
+ { "bootp", HAS_ARG, QEMU_OPTION_bootp },
#ifndef _WIN32
{ "smb", HAS_ARG, QEMU_OPTION_smb },
#endif
@@ -6572,12 +6915,14 @@
#endif
{ "localtime", 0, QEMU_OPTION_localtime },
{ "std-vga", 0, QEMU_OPTION_std_vga },
+ { "echr", 1, QEMU_OPTION_echr },
{ "monitor", 1, QEMU_OPTION_monitor },
{ "serial", 1, QEMU_OPTION_serial },
{ "parallel", 1, QEMU_OPTION_parallel },
{ "loadvm", HAS_ARG, QEMU_OPTION_loadvm },
{ "full-screen", 0, QEMU_OPTION_full_screen },
#ifdef CONFIG_SDL
+ { "no-frame", 0, QEMU_OPTION_no_frame },
{ "no-quit", 0, QEMU_OPTION_no_quit },
#endif
{ "pidfile", HAS_ARG, QEMU_OPTION_pidfile },
@@ -6590,11 +6935,19 @@
/* temporary options */
{ "usb", 0, QEMU_OPTION_usb },
{ "cirrusvga", 0, QEMU_OPTION_cirrusvga },
+ { "vmwarevga", 0, QEMU_OPTION_vmsvga },
{ "no-acpi", 0, QEMU_OPTION_no_acpi },
{ "no-reboot", 0, QEMU_OPTION_no_reboot },
{ "show-cursor", 0, QEMU_OPTION_show_cursor },
{ "daemonize", 0, QEMU_OPTION_daemonize },
{ "option-rom", HAS_ARG, QEMU_OPTION_option_rom },
+#if defined(TARGET_ARM)
+ { "semihosting", 0, QEMU_OPTION_semihosting },
+#endif
+ { "name", HAS_ARG, QEMU_OPTION_name },
+#if defined(TARGET_SPARC)
+ { "prom-env", HAS_ARG, QEMU_OPTION_prom_env },
+#endif
{ NULL },
};
@@ -6663,27 +7016,33 @@
qemu_register_machine(&heathrow_machine);
qemu_register_machine(&core99_machine);
qemu_register_machine(&prep_machine);
+ qemu_register_machine(&ref405ep_machine);
+ qemu_register_machine(&taihu_machine);
#elif defined(TARGET_MIPS)
qemu_register_machine(&mips_machine);
+ qemu_register_machine(&mips_malta_machine);
+ qemu_register_machine(&mips_pica61_machine);
#elif defined(TARGET_SPARC)
#ifdef TARGET_SPARC64
qemu_register_machine(&sun4u_machine);
#else
- qemu_register_machine(&sun4m_machine);
+ qemu_register_machine(&ss5_machine);
+ qemu_register_machine(&ss10_machine);
#endif
#elif defined(TARGET_ARM)
- qemu_register_machine(&integratorcp926_machine);
- qemu_register_machine(&integratorcp1026_machine);
+ qemu_register_machine(&integratorcp_machine);
qemu_register_machine(&versatilepb_machine);
qemu_register_machine(&versatileab_machine);
qemu_register_machine(&realview_machine);
- qemu_register_machine(&zaurusakita_machine);
- qemu_register_machine(&zaurusspitz_machine);
- qemu_register_machine(&zaurusborzoi_machine);
- qemu_register_machine(&zaurusterrier_machine);
+ qemu_register_machine(&akitapda_machine);
+ qemu_register_machine(&spitzpda_machine);
+ qemu_register_machine(&borzoipda_machine);
+ qemu_register_machine(&terrierpda_machine);
qemu_register_machine(&neo1973_machine);
#elif defined(TARGET_SH4)
qemu_register_machine(&shix_machine);
+#elif defined(TARGET_ALPHA)
+ /* XXX: TODO */
#else
#error unsupported CPU
#endif
@@ -6817,16 +7176,19 @@
int main(int argc, char **argv)
{
#ifdef CONFIG_GDBSTUB
- int use_gdbstub, gdbstub_port;
+ int use_gdbstub;
+ const char *gdbstub_port;
#endif
- int i, cdrom_index;
- int linux_boot;
+ int i, cdrom_index, pflash_index;
+ int snapshot, linux_boot;
const char *initrd_filename;
const char *hd_filename[MAX_DISKS], *fd_filename[MAX_FD];
+ const char *pflash_filename[MAX_PFLASH];
+ const char *sd_filename;
+ const char *mtd_filename;
const char *kernel_filename, *kernel_cmdline;
DisplayState *ds = &display_state;
int cyls, heads, secs, translation;
- int start_emulation = 1;
char net_clients[MAX_NET_CLIENTS][256];
int nb_net_clients;
int optind;
@@ -6839,10 +7201,12 @@
int parallel_device_index;
const char *loadvm = NULL;
QEMUMachine *machine;
+ const char *cpu_model;
char usb_devices[MAX_USB_CMDLINE][128];
int usb_devices_index;
int usbgadget_enabled = 0;
int fds[2];
+ const char *pid_file = NULL;
LIST_INIT (&vm_change_state_head);
#ifndef _WIN32
@@ -6877,14 +7241,19 @@
register_machines();
machine = first_machine;
+ cpu_model = NULL;
initrd_filename = NULL;
for(i = 0; i < MAX_FD; i++)
fd_filename[i] = NULL;
for(i = 0; i < MAX_DISKS; i++)
hd_filename[i] = NULL;
+ for(i = 0; i < MAX_PFLASH; i++)
+ pflash_filename[i] = NULL;
+ pflash_index = 0;
+ sd_filename = NULL;
+ mtd_filename = NULL;
ram_size = DEFAULT_RAM_SIZE * 1024 * 1024;
vga_ram_size = VGA_RAM_SIZE;
- bios_size = BIOS_SIZE;
#ifdef CONFIG_GDBSTUB
use_gdbstub = 0;
gdbstub_port = DEFAULT_GDBSTUB_PORT;
@@ -6930,6 +7299,9 @@
const QEMUOption *popt;
optind++;
+ /* Treat --foo the same as -foo. */
+ if (r[1] == '-')
+ r++;
popt = qemu_options;
for(;;) {
if (!popt->name) {
@@ -6966,6 +7338,23 @@
exit(1);
}
break;
+ case QEMU_OPTION_cpu:
+ /* hw initialization will check this */
+ if (optarg[0] == '?') {
+#if defined(TARGET_PPC)
+ ppc_cpu_list(stdout, &fprintf);
+#elif defined(TARGET_ARM)
+ arm_cpu_list();
+#elif defined(TARGET_MIPS)
+ mips_cpu_list(stdout, &fprintf);
+#elif defined(TARGET_SPARC)
+ sparc_cpu_list(stdout, &fprintf);
+#endif
+ exit(1);
+ } else {
+ cpu_model = optarg;
+ }
+ break;
case QEMU_OPTION_initrd:
initrd_filename = optarg;
break;
@@ -6987,6 +7376,13 @@
case QEMU_OPTION_sd:
sd_filename = optarg;
break;
+ case QEMU_OPTION_pflash:
+ if (pflash_index >= MAX_PFLASH) {
+ fprintf(stderr, "qemu: too many parallel flash images\n");
+ exit(1);
+ }
+ pflash_filename[pflash_index++] = optarg;
+ break;
case QEMU_OPTION_snapshot:
snapshot = 1;
break;
@@ -7027,11 +7423,12 @@
}
break;
case QEMU_OPTION_nographic:
+ pstrcpy(serial_devices[0], sizeof(serial_devices[0]), "stdio");
+ pstrcpy(parallel_devices[0], sizeof(parallel_devices[0]), "null");
pstrcpy(monitor_device, sizeof(monitor_device), "stdio");
- pstrcpy(serial_devices[0], sizeof(serial_devices[0]), "stdio");
nographic = 1;
break;
- case QEMU_OPTION_vertical:
+ case QEMU_OPTION_portrait:
graphic_rotate = 1;
break;
case QEMU_OPTION_kernel:
@@ -7085,6 +7482,9 @@
case QEMU_OPTION_tftp:
tftp_prefix = optarg;
break;
+ case QEMU_OPTION_bootp:
+ bootp_filename = optarg;
+ break;
#ifndef _WIN32
case QEMU_OPTION_smb:
net_slirp_smb(optarg);
@@ -7137,14 +7537,14 @@
use_gdbstub = 1;
break;
case QEMU_OPTION_p:
- gdbstub_port = atoi(optarg);
+ gdbstub_port = optarg;
break;
#endif
case QEMU_OPTION_L:
bios_dir = optarg;
break;
case QEMU_OPTION_S:
- start_emulation = 0;
+ autostart = 0;
break;
case QEMU_OPTION_k:
keyboard_layout = optarg;
@@ -7154,9 +7554,15 @@
break;
case QEMU_OPTION_cirrusvga:
cirrus_vga_enabled = 1;
+ vmsvga_enabled = 0;
break;
+ case QEMU_OPTION_vmsvga:
+ cirrus_vga_enabled = 0;
+ vmsvga_enabled = 1;
+ break;
case QEMU_OPTION_std_vga:
cirrus_vga_enabled = 0;
+ vmsvga_enabled = 0;
break;
case QEMU_OPTION_g:
{
@@ -7192,6 +7598,14 @@
graphic_depth = depth;
}
break;
+ case QEMU_OPTION_echr:
+ {
+ char *r;
+ term_escape_char = strtol(optarg, &r, 0);
+ if (r == optarg)
+ printf("Bad argument to echr\n");
+ break;
+ }
case QEMU_OPTION_monitor:
pstrcpy(monitor_device, sizeof(monitor_device), optarg);
break;
@@ -7220,12 +7634,15 @@
full_screen = 1;
break;
#ifdef CONFIG_SDL
+ case QEMU_OPTION_no_frame:
+ no_frame = 1;
+ break;
case QEMU_OPTION_no_quit:
no_quit = 1;
break;
#endif
case QEMU_OPTION_pidfile:
- create_pidfile(optarg);
+ pid_file = optarg;
break;
#ifdef TARGET_I386
case QEMU_OPTION_win2k_hack:
@@ -7287,6 +7704,22 @@
option_rom[nb_option_roms] = optarg;
nb_option_roms++;
break;
+ case QEMU_OPTION_semihosting:
+ semihosting_enabled = 1;
+ break;
+ case QEMU_OPTION_name:
+ qemu_name = optarg;
+ break;
+#ifdef TARGET_SPARC
+ case QEMU_OPTION_prom_env:
+ if (nb_prom_envs >= MAX_PROM_ENVS) {
+ fprintf(stderr, "Too many prom variables\n");
+ exit(1);
+ }
+ prom_envs[nb_prom_envs] = optarg;
+ nb_prom_envs++;
+ break;
+#endif
}
}
}
@@ -7311,16 +7744,19 @@
close(fds[1]);
again:
- len = read(fds[0], &status, 1);
- if (len == -1 && (errno == EINTR))
- goto again;
-
- if (len != 1 || status != 0)
- exit(1);
- else
- exit(0);
+ len = read(fds[0], &status, 1);
+ if (len == -1 && (errno == EINTR))
+ goto again;
+
+ if (len != 1)
+ exit(1);
+ else if (status == 1) {
+ fprintf(stderr, "Could not acquire pidfile\n");
+ exit(1);
+ } else
+ exit(0);
} else if (pid < 0)
- exit(1);
+ exit(1);
setsid();
@@ -7339,6 +7775,15 @@
}
#endif
+ if (pid_file && qemu_create_pidfile(pid_file) != 0) {
+ if (daemonize) {
+ uint8_t status = 1;
+ write(fds[1], &status, 1);
+ } else
+ fprintf(stderr, "Could not acquire pid file\n");
+ exit(1);
+ }
+
#ifdef USE_KQEMU
if (smp_cpus > 1)
kqemu_allowed = 0;
@@ -7346,6 +7791,7 @@
linux_boot = (kernel_filename != NULL);
if (!linux_boot &&
+ boot_device != 'n' &&
hd_filename[0] == '\0' &&
(cdrom_index >= 0 && hd_filename[cdrom_index] == '\0') &&
fd_filename[0] == '\0')
@@ -7407,17 +7853,8 @@
#endif
/* init the memory */
- phys_ram_size = ram_size + vga_ram_size + bios_size;
+ phys_ram_size = ram_size + vga_ram_size + MAX_BIOS_SIZE;
- for (i = 0; i < nb_option_roms; i++) {
- int ret = get_image_size(option_rom[i]);
- if (ret == -1) {
- fprintf(stderr, "Could not load option rom '%s'\n", option_rom[i]);
- exit(1);
- }
- phys_ram_size += ret;
- }
-
phys_ram_base = qemu_vmalloc(phys_ram_size);
if (!phys_ram_base) {
fprintf(stderr, "Could not allocate physical memory\n");
@@ -7474,6 +7911,48 @@
}
}
+ /* Open the virtual parallel flash block devices */
+ for(i = 0; i < MAX_PFLASH; i++) {
+ if (pflash_filename[i]) {
+ if (!pflash_table[i]) {
+ char buf[64];
+ snprintf(buf, sizeof(buf), "fl%c", i + 'a');
+ pflash_table[i] = bdrv_new(buf);
+ }
+ if (bdrv_open(pflash_table[i], pflash_filename[i],
+ snapshot ? BDRV_O_SNAPSHOT : 0) < 0) {
+ fprintf(stderr, "qemu: could not open flash image '%s'\n",
+ pflash_filename[i]);
+ exit(1);
+ }
+ }
+ }
+
+ sd_bdrv = bdrv_new ("sd");
+ /* FIXME: This isn't really a floppy, but it's a reasonable
+ approximation. */
+ bdrv_set_type_hint(sd_bdrv, BDRV_TYPE_FLOPPY);
+ if (sd_filename) {
+ if (bdrv_open(sd_bdrv, sd_filename,
+ snapshot ? BDRV_O_SNAPSHOT : 0) < 0) {
+ fprintf(stderr, "qemu: could not open SD card image %s\n",
+ sd_filename);
+ } else
+ qemu_key_check(sd_bdrv, sd_filename);
+ }
+
+ if (mtd_filename) {
+ mtd_bdrv = bdrv_new ("mtd");
+ if (bdrv_open(mtd_bdrv, mtd_filename,
+ snapshot ? BDRV_O_SNAPSHOT : 0) < 0 ||
+ qemu_key_check(mtd_bdrv, mtd_filename)) {
+ fprintf(stderr, "qemu: could not open Flash image %s\n",
+ mtd_filename);
+ bdrv_delete(mtd_bdrv);
+ mtd_bdrv = 0;
+ }
+ }
+
register_savevm("timer", 0, 2, timer_save, timer_load, NULL);
register_savevm("ram", 0, 2, ram_save, ram_load, NULL);
@@ -7486,7 +7965,7 @@
vnc_display_init(ds, vnc_display);
} else {
#if defined(CONFIG_SDL)
- sdl_display_init(ds, full_screen);
+ sdl_display_init(ds, full_screen, no_frame);
#elif defined(CONFIG_COCOA)
cocoa_display_init(ds, full_screen);
#else
@@ -7494,12 +7973,27 @@
#endif
}
- monitor_hd = qemu_chr_open(monitor_device);
- if (!monitor_hd) {
- fprintf(stderr, "qemu: could not open monitor device '%s'\n", monitor_device);
- exit(1);
+ /* Maintain compatibility with multiple stdio monitors */
+ if (!strcmp(monitor_device,"stdio")) {
+ for (i = 0; i < MAX_SERIAL_PORTS; i++) {
+ if (!strcmp(serial_devices[i],"mon:stdio")) {
+ monitor_device[0] = '\0';
+ break;
+ } else if (!strcmp(serial_devices[i],"stdio")) {
+ monitor_device[0] = '\0';
+ pstrcpy(serial_devices[0], sizeof(serial_devices[0]), "mon:stdio");
+ break;
+ }
+ }
}
- monitor_init(monitor_hd, !nographic);
+ if (monitor_device[0] != '\0') {
+ monitor_hd = qemu_chr_open(monitor_device);
+ if (!monitor_hd) {
+ fprintf(stderr, "qemu: could not open monitor device '%s'\n", monitor_device);
+ exit(1);
+ }
+ monitor_init(monitor_hd, !nographic);
+ }
for(i = 0; i < MAX_SERIAL_PORTS; i++) {
const char *devname = serial_devices[i];
@@ -7531,7 +8025,7 @@
machine->init(ram_size, vga_ram_size, boot_device,
ds, fd_filename, snapshot,
- kernel_filename, kernel_cmdline, initrd_filename);
+ kernel_filename, kernel_cmdline, initrd_filename, cpu_model);
/* init USB devices */
if (usb_enabled) {
@@ -7554,12 +8048,12 @@
#ifdef CONFIG_GDBSTUB
if (use_gdbstub) {
+ /* XXX: use standard host:port notation and modify options
+ accordingly. */
if (gdbserver_start(gdbstub_port) < 0) {
- fprintf(stderr, "Could not open gdbserver socket on port %d\n",
+ fprintf(stderr, "qemu: could not open gdbstub device on port '%s'\n",
gdbstub_port);
exit(1);
- } else {
- printf("Waiting gdb connection on port %d\n", gdbstub_port);
}
} else
#endif
@@ -7569,7 +8063,7 @@
{
/* XXX: simplify init */
read_passwords();
- if (start_emulation) {
+ if (autostart) {
vm_start();
}
}
Modified: trunk/src/host/qemu-neo1973/vl.h
===================================================================
--- trunk/src/host/qemu-neo1973/vl.h 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/vl.h 2007-05-11 23:44:50 UTC (rev 1948)
@@ -45,8 +45,8 @@
#define O_BINARY 0
#endif
-#ifdef __sun__
-#define ENOMEDIUM 4097
+#ifndef ENOMEDIUM
+#define ENOMEDIUM ENODEV
#endif
#ifdef _WIN32
@@ -54,7 +54,6 @@
#define fsync _commit
#define lseek _lseeki64
#define ENOTSUP 4096
-#define ENOMEDIUM 4097
extern int qemu_ftruncate64(int, int64_t);
#define ftruncate qemu_ftruncate64
@@ -84,7 +83,6 @@
#include "audio/audio.h"
#include "cpu.h"
-#include "gdbstub.h"
#endif /* !defined(QEMU_TOOL) */
@@ -116,6 +114,7 @@
extern const char *bios_dir;
extern int vm_running;
+extern const char *qemu_name;
typedef struct vm_change_state_entry VMChangeStateEntry;
typedef void VMChangeStateHandler(void *opaque, int running);
@@ -150,6 +149,7 @@
extern int bios_size;
extern int rtc_utc;
extern int cirrus_vga_enabled;
+extern int vmsvga_enabled;
extern int graphic_width;
extern int graphic_height;
extern int graphic_depth;
@@ -159,23 +159,28 @@
extern int usb_enabled;
extern int smp_cpus;
extern int cursor_hide;
-extern int snapshot;
-extern const char *sd_filename;
-extern const char *mtd_filename;
extern int graphic_rotate;
extern int no_quit;
+extern int semihosting_enabled;
+extern int autostart;
+extern const char *bootp_filename;
#define MAX_OPTION_ROMS 16
extern const char *option_rom[MAX_OPTION_ROMS];
extern int nb_option_roms;
+#ifdef TARGET_SPARC
+#define MAX_PROM_ENVS 128
+extern const char *prom_envs[MAX_PROM_ENVS];
+extern unsigned int nb_prom_envs;
+#endif
+
/* XXX: make it dynamic */
+#define MAX_BIOS_SIZE (4 * 1024 * 1024)
#if defined (TARGET_PPC) || defined (TARGET_SPARC64)
#define BIOS_SIZE ((512 + 32) * 1024)
#elif defined(TARGET_MIPS)
-#define BIOS_SIZE (128 * 1024)
-#else
-#define BIOS_SIZE ((256 + 64) * 1024)
+#define BIOS_SIZE (4 * 1024 * 1024)
#endif
/* keyboard/mouse support */
@@ -291,33 +296,43 @@
#define CHR_IOCTL_PP_READ_CONTROL 5
#define CHR_IOCTL_PP_WRITE_CONTROL 6
#define CHR_IOCTL_PP_READ_STATUS 7
+#define CHR_IOCTL_PP_EPP_READ_ADDR 8
+#define CHR_IOCTL_PP_EPP_READ 9
+#define CHR_IOCTL_PP_EPP_WRITE_ADDR 10
+#define CHR_IOCTL_PP_EPP_WRITE 11
-#define CHR_IOCTL_MODEM_HANDSHAKE 8
+#define CHR_IOCTL_MODEM_HANDSHAKE 12
typedef void IOEventHandler(void *opaque, int event);
typedef struct CharDriverState {
int (*chr_write)(struct CharDriverState *s, const uint8_t *buf, int len);
- void (*chr_add_read_handler)(struct CharDriverState *s,
- IOCanRWHandler *fd_can_read,
- IOReadHandler *fd_read, void *opaque);
+ void (*chr_update_read_handler)(struct CharDriverState *s);
int (*chr_ioctl)(struct CharDriverState *s, int cmd, void *arg);
IOEventHandler *chr_event;
+ IOCanRWHandler *chr_can_read;
+ IOReadHandler *chr_read;
+ void *handler_opaque;
void (*chr_send_event)(struct CharDriverState *chr, int event);
void (*chr_close)(struct CharDriverState *chr);
void *opaque;
+ int focus;
QEMUBH *bh;
} CharDriverState;
+CharDriverState *qemu_chr_open(const char *filename);
void qemu_chr_printf(CharDriverState *s, const char *fmt, ...);
int qemu_chr_write(CharDriverState *s, const uint8_t *buf, int len);
void qemu_chr_send_event(CharDriverState *s, int event);
-void qemu_chr_add_read_handler(CharDriverState *s,
- IOCanRWHandler *fd_can_read,
- IOReadHandler *fd_read, void *opaque);
-void qemu_chr_add_event_handler(CharDriverState *s, IOEventHandler *chr_event);
+void qemu_chr_add_handlers(CharDriverState *s,
+ IOCanRWHandler *fd_can_read,
+ IOReadHandler *fd_read,
+ IOEventHandler *fd_event,
+ void *opaque);
int qemu_chr_ioctl(CharDriverState *s, int cmd, void *arg);
void qemu_chr_reset(CharDriverState *s);
+int qemu_chr_can_read(CharDriverState *s);
+void qemu_chr_read(CharDriverState *s, uint8_t *buf, int len);
/* consoles */
@@ -352,6 +367,11 @@
extern CharDriverState *parallel_hds[MAX_PARALLEL_PORTS];
+struct ParallelIOArg {
+ void *buffer;
+ int count;
+};
+
/* VLANs support */
typedef struct VLANClientState VLANClientState;
@@ -689,7 +709,7 @@
int boot_device,
DisplayState *ds, const char **fd_filename, int snapshot,
const char *kernel_filename, const char *kernel_cmdline,
- const char *initrd_filename);
+ const char *initrd_filename, const char *cpu_model);
typedef struct QEMUMachine {
const char *name;
@@ -701,8 +721,17 @@
int qemu_register_machine(QEMUMachine *m);
typedef void SetIRQFunc(void *opaque, int irq_num, int level);
-typedef void IRQRequestFunc(void *opaque, int level);
+#if defined(TARGET_PPC)
+void ppc_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...));
+#endif
+
+#if defined(TARGET_MIPS)
+void mips_cpu_list (FILE *f, int (*cpu_fprintf)(FILE *f, const char *fmt, ...));
+#endif
+
+#include "hw/irq.h"
+
/* ISA bus */
extern target_phys_addr_t isa_mem_base;
@@ -775,6 +804,9 @@
/* ??? This is a PC-specific hack, and should be removed. */
int irq_index;
+ /* IRQ objects for the INTA-INTD pins. */
+ qemu_irq *irq;
+
/* Current IRQ levels. Used internally by the generic PCI code. */
int irq_state[4];
};
@@ -788,8 +820,6 @@
uint32_t size, int type,
PCIMapIORegionFunc *map_func);
-void pci_set_irq(PCIDevice *pci_dev, int irq_num, int level);
-
uint32_t pci_default_read_config(PCIDevice *d,
uint32_t address, int len);
void pci_default_write_config(PCIDevice *d,
@@ -797,12 +827,12 @@
void pci_device_save(PCIDevice *s, QEMUFile *f);
int pci_device_load(PCIDevice *s, QEMUFile *f);
-typedef void (*pci_set_irq_fn)(void *pic, int irq_num, int level);
+typedef void (*pci_set_irq_fn)(qemu_irq *pic, int irq_num, int level);
typedef int (*pci_map_irq_fn)(PCIDevice *pci_dev, int irq_num);
PCIBus *pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
- void *pic, int devfn_min, int nirq);
+ qemu_irq *pic, int devfn_min, int nirq);
-void pci_nic_init(PCIBus *bus, NICInfo *nd);
+void pci_nic_init(PCIBus *bus, NICInfo *nd, int devfn);
void pci_data_write(void *opaque, uint32_t addr, uint32_t val, int len);
uint32_t pci_data_read(void *opaque, uint32_t addr, int len);
int pci_bus_num(PCIBus *s);
@@ -813,37 +843,47 @@
pci_map_irq_fn map_irq, const char *name);
/* prep_pci.c */
-PCIBus *pci_prep_init(void);
+PCIBus *pci_prep_init(qemu_irq *pic);
/* grackle_pci.c */
-PCIBus *pci_grackle_init(uint32_t base, void *pic);
+PCIBus *pci_grackle_init(uint32_t base, qemu_irq *pic);
/* unin_pci.c */
-PCIBus *pci_pmac_init(void *pic);
+PCIBus *pci_pmac_init(qemu_irq *pic);
/* apb_pci.c */
PCIBus *pci_apb_init(target_ulong special_base, target_ulong mem_base,
- void *pic);
+ qemu_irq *pic);
-PCIBus *pci_vpb_init(void *pic, int irq, int realview);
+PCIBus *pci_vpb_init(qemu_irq *pic, int irq, int realview);
/* piix_pci.c */
-PCIBus *i440fx_init(PCIDevice **pi440fx_state);
+PCIBus *i440fx_init(PCIDevice **pi440fx_state, qemu_irq *pic);
void i440fx_set_smm(PCIDevice *d, int val);
-int piix3_init(PCIBus *bus);
+int piix3_init(PCIBus *bus, int devfn);
void i440fx_init_memory_mappings(PCIDevice *d);
+int piix4_init(PCIBus *bus, int devfn);
+
/* openpic.c */
-typedef struct openpic_t openpic_t;
-void openpic_set_irq(void *opaque, int n_IRQ, int level);
-openpic_t *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus,
- CPUState **envp);
+/* OpenPIC have 5 outputs per CPU connected and one IRQ out single output */
+enum {
+ OPENPIC_OUTPUT_INT = 0, /* IRQ */
+ OPENPIC_OUTPUT_CINT, /* critical IRQ */
+ OPENPIC_OUTPUT_MCK, /* Machine check event */
+ OPENPIC_OUTPUT_DEBUG, /* Inconditional debug event */
+ OPENPIC_OUTPUT_RESET, /* Core reset event */
+ OPENPIC_OUTPUT_NB,
+};
+qemu_irq *openpic_init (PCIBus *bus, int *pmem_index, int nb_cpus,
+ qemu_irq **irqs, qemu_irq irq_out);
/* heathrow_pic.c */
-typedef struct HeathrowPICS HeathrowPICS;
-void heathrow_pic_set_irq(void *opaque, int num, int level);
-HeathrowPICS *heathrow_pic_init(int *pmem_index);
+qemu_irq *heathrow_pic_init(int *pmem_index);
+/* gt64xxx.c */
+PCIBus *pci_gt64120_init(qemu_irq *pic);
+
#ifdef HAS_AUDIO
struct soundhw {
const char *name;
@@ -851,7 +891,7 @@
int enabled;
int isa;
union {
- int (*init_isa) (AudioState *s);
+ int (*init_isa) (AudioState *s, qemu_irq *pic);
int (*init_pci) (PCIBus *bus, AudioState *s);
} init;
};
@@ -861,7 +901,11 @@
/* vga.c */
+#ifndef TARGET_SPARC
#define VGA_RAM_SIZE (8192 * 1024)
+#else
+#define VGA_RAM_SIZE (9 * 1024 * 1024)
+#endif
struct DisplayState {
uint8_t *data;
@@ -875,7 +919,13 @@
void (*dpy_update)(struct DisplayState *s, int x, int y, int w, int h);
void (*dpy_resize)(struct DisplayState *s, int w, int h);
void (*dpy_refresh)(struct DisplayState *s);
- void (*dpy_copy)(struct DisplayState *s, int src_x, int src_y, int dst_x, int dst_y, int w, int h);
+ void (*dpy_copy)(struct DisplayState *s, int src_x, int src_y,
+ int dst_x, int dst_y, int w, int h);
+ void (*dpy_fill)(struct DisplayState *s, int x, int y,
+ int w, int h, uint32_t c);
+ void (*mouse_set)(int x, int y, int on);
+ void (*cursor_define)(int width, int height, int bpp, int hot_x, int hot_y,
+ uint8_t *image, uint8_t *mask);
};
static inline void dpy_update(DisplayState *s, int x, int y, int w, int h)
@@ -893,6 +943,10 @@
int pci_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base,
unsigned long vga_ram_offset, int vga_ram_size,
unsigned long vga_bios_offset, int vga_bios_size);
+int isa_vga_mm_init(DisplayState *ds, uint8_t *vga_ram_base,
+ unsigned long vga_ram_offset, int vga_ram_size,
+ target_phys_addr_t vram_base, target_phys_addr_t ctrl_base,
+ int it_shift);
/* cirrus_vga.c */
void pci_cirrus_vga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base,
@@ -900,43 +954,57 @@
void isa_cirrus_vga_init(DisplayState *ds, uint8_t *vga_ram_base,
unsigned long vga_ram_offset, int vga_ram_size);
+/* vmware_vga.c */
+void pci_vmsvga_init(PCIBus *bus, DisplayState *ds, uint8_t *vga_ram_base,
+ unsigned long vga_ram_offset, int vga_ram_size);
+
/* sdl.c */
-void sdl_display_init(DisplayState *ds, int full_screen);
+void sdl_display_init(DisplayState *ds, int full_screen, int no_frame);
/* cocoa.m */
void cocoa_display_init(DisplayState *ds, int full_screen);
/* vnc.c */
void vnc_display_init(DisplayState *ds, const char *display);
+void do_info_vnc(void);
+/* x_keymap.c */
+extern uint8_t _translate_keycode(const int key);
+
/* ide.c */
#define MAX_DISKS 4
extern BlockDriverState *bs_table[MAX_DISKS + 1];
+extern BlockDriverState *sd_bdrv;
+extern BlockDriverState *mtd_bdrv;
-void isa_ide_init(int iobase, int iobase2, int irq,
+void isa_ide_init(int iobase, int iobase2, qemu_irq irq,
BlockDriverState *hd0, BlockDriverState *hd1);
void pci_cmd646_ide_init(PCIBus *bus, BlockDriverState **hd_table,
int secondary_ide_enabled);
-void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn);
-int pmac_ide_init (BlockDriverState **hd_table,
- SetIRQFunc *set_irq, void *irq_opaque, int irq);
+void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn,
+ qemu_irq *pic);
+int pmac_ide_init (BlockDriverState **hd_table, qemu_irq irq);
/* cdrom.c */
int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track);
int cdrom_read_toc_raw(int nb_sectors, uint8_t *buf, int msf, int session_num);
+/* ds1225y.c */
+typedef struct ds1225y_t ds1225y_t;
+ds1225y_t *ds1225y_init(target_ulong mem_base, const char *filename);
+
/* es1370.c */
int es1370_init (PCIBus *bus, AudioState *s);
/* sb16.c */
-int SB16_init (AudioState *s);
+int SB16_init (AudioState *s, qemu_irq *pic);
/* adlib.c */
-int Adlib_init (AudioState *s);
+int Adlib_init (AudioState *s, qemu_irq *pic);
/* gus.c */
-int GUS_init (AudioState *s);
+int GUS_init (AudioState *s, qemu_irq *pic);
/* dma.c */
typedef int (*DMA_transfer_handler) (void *opaque, int nchan, int pos, int size);
@@ -957,52 +1025,67 @@
typedef struct fdctrl_t fdctrl_t;
-fdctrl_t *fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped,
+fdctrl_t *fdctrl_init (qemu_irq irq, int dma_chann, int mem_mapped,
uint32_t io_base,
BlockDriverState **fds);
int fdctrl_get_drive_type(fdctrl_t *fdctrl, int drive_num);
+/* eepro100.c */
+
+void pci_i82551_init(PCIBus *bus, NICInfo *nd, int devfn);
+void pci_i82557b_init(PCIBus *bus, NICInfo *nd, int devfn);
+void pci_i82559er_init(PCIBus *bus, NICInfo *nd, int devfn);
+
/* ne2000.c */
-void isa_ne2000_init(int base, int irq, NICInfo *nd);
-void pci_ne2000_init(PCIBus *bus, NICInfo *nd);
+void isa_ne2000_init(int base, qemu_irq irq, NICInfo *nd);
+void pci_ne2000_init(PCIBus *bus, NICInfo *nd, int devfn);
/* rtl8139.c */
-void pci_rtl8139_init(PCIBus *bus, NICInfo *nd);
+void pci_rtl8139_init(PCIBus *bus, NICInfo *nd, int devfn);
/* pcnet.c */
-void pci_pcnet_init(PCIBus *bus, NICInfo *nd);
+void pci_pcnet_init(PCIBus *bus, NICInfo *nd, int devfn);
void pcnet_h_reset(void *opaque);
-void *lance_init(NICInfo *nd, uint32_t leaddr, void *dma_opaque);
+void *lance_init(NICInfo *nd, uint32_t leaddr, void *dma_opaque, qemu_irq irq);
+/* vmmouse.c */
+void *vmmouse_init(void *m);
/* pckbd.c */
-void kbd_init(void);
+void i8042_init(qemu_irq kbd_irq, qemu_irq mouse_irq, uint32_t io_base);
+void i8042_mm_init(qemu_irq kbd_irq, qemu_irq mouse_irq, target_ulong base, int it_shift);
/* mc146818rtc.c */
typedef struct RTCState RTCState;
-RTCState *rtc_init(int base, int irq);
+RTCState *rtc_init(int base, qemu_irq irq);
+RTCState *rtc_mm_init(target_phys_addr_t base, int it_shift, qemu_irq irq);
void rtc_set_memory(RTCState *s, int addr, int val);
void rtc_set_date(RTCState *s, const struct tm *tm);
/* serial.c */
typedef struct SerialState SerialState;
-SerialState *serial_init(SetIRQFunc *set_irq, void *opaque,
- int base, int irq, CharDriverState *chr);
-SerialState *serial_mm_init (SetIRQFunc *set_irq, void *opaque,
- target_ulong base, int it_shift,
- int irq, CharDriverState *chr);
+SerialState *serial_init(int base, qemu_irq irq, CharDriverState *chr);
+SerialState *serial_mm_init (target_ulong base, int it_shift,
+ qemu_irq irq, CharDriverState *chr,
+ int ioregister);
+uint32_t serial_mm_readb (void *opaque, target_phys_addr_t addr);
+void serial_mm_writeb (void *opaque, target_phys_addr_t addr, uint32_t value);
+uint32_t serial_mm_readw (void *opaque, target_phys_addr_t addr);
+void serial_mm_writew (void *opaque, target_phys_addr_t addr, uint32_t value);
+uint32_t serial_mm_readl (void *opaque, target_phys_addr_t addr);
+void serial_mm_writel (void *opaque, target_phys_addr_t addr, uint32_t value);
/* parallel.c */
typedef struct ParallelState ParallelState;
-ParallelState *parallel_init(int base, int irq, CharDriverState *chr);
+ParallelState *parallel_init(int base, qemu_irq irq, CharDriverState *chr);
/* i8259.c */
@@ -1010,7 +1093,7 @@
extern PicState2 *isa_pic;
void pic_set_irq(int irq, int level);
void pic_set_irq_new(void *opaque, int irq, int level);
-PicState2 *pic_init(IRQRequestFunc *irq_request, void *irq_request_opaque);
+qemu_irq *i8259_init(qemu_irq parent_irq);
void pic_set_alt_irq_func(PicState2 *s, SetIRQFunc *alt_irq_func,
void *alt_irq_opaque);
int pic_read_irq(PicState2 *s);
@@ -1033,7 +1116,7 @@
typedef struct PITState PITState;
-PITState *pit_init(int base, int irq);
+PITState *pit_init(int base, qemu_irq irq);
void pit_set_gate(PITState *pit, int channel, int val);
int pit_get_gate(PITState *pit, int channel);
int pit_get_initial_count(PITState *pit, int channel);
@@ -1042,11 +1125,19 @@
/* pcspk.c */
void pcspk_init(PITState *);
-int pcspk_audio_init(AudioState *);
+int pcspk_audio_init(AudioState *, qemu_irq *pic);
+/* GPIO */
+typedef void (*gpio_handler_t)(int line, int level, void *opaque);
+
+#include "hw/i2c.h"
+
+#include "hw/smbus.h"
+
/* acpi.c */
extern int acpi_enabled;
-void piix4_pm_init(PCIBus *bus, int devfn);
+i2c_bus *piix4_pm_init(PCIBus *bus, int devfn);
+void piix4_smbus_register_device(SMBusDevice *dev, uint8_t addr);
void acpi_bios_init(void);
/* pc.c */
@@ -1061,10 +1152,21 @@
extern QEMUMachine prep_machine;
extern QEMUMachine core99_machine;
extern QEMUMachine heathrow_machine;
+extern QEMUMachine ref405ep_machine;
+extern QEMUMachine taihu_machine;
/* mips_r4k.c */
extern QEMUMachine mips_machine;
+/* mips_malta.c */
+extern QEMUMachine mips_malta_machine;
+
+/* mips_int.c */
+extern void cpu_mips_irq_init_cpu(CPUState *env);
+
+/* mips_pica61.c */
+extern QEMUMachine mips_pica61_machine;
+
/* mips_timer.c */
extern void cpu_mips_clock_init(CPUState *);
extern void cpu_mips_irqctrl_init (void);
@@ -1073,7 +1175,32 @@
extern QEMUMachine shix_machine;
#ifdef TARGET_PPC
-ppc_tb_t *cpu_ppc_tb_init (CPUState *env, uint32_t freq);
+/* PowerPC hardware exceptions management helpers */
+typedef void (*clk_setup_cb)(void *opaque, uint32_t freq);
+typedef struct clk_setup_t clk_setup_t;
+struct clk_setup_t {
+ clk_setup_cb cb;
+ void *opaque;
+};
+static inline void clk_setup (clk_setup_t *clk, uint32_t freq)
+{
+ if (clk->cb != NULL)
+ (*clk->cb)(clk->opaque, freq);
+}
+
+clk_setup_cb cpu_ppc_tb_init (CPUState *env, uint32_t freq);
+/* Embedded PowerPC DCR management */
+typedef target_ulong (*dcr_read_cb)(void *opaque, int dcrn);
+typedef void (*dcr_write_cb)(void *opaque, int dcrn, target_ulong val);
+int ppc_dcr_init (CPUState *env, int (*dcr_read_error)(int dcrn),
+ int (*dcr_write_error)(int dcrn));
+int ppc_dcr_register (CPUState *env, int dcrn, void *opaque,
+ dcr_read_cb drc_read, dcr_write_cb dcr_write);
+clk_setup_cb ppc_emb_timers_init (CPUState *env, uint32_t freq);
+/* Embedded PowerPC reset */
+void ppc40x_core_reset (CPUState *env);
+void ppc40x_chip_reset (CPUState *env);
+void ppc40x_system_reset (CPUState *env);
#endif
void PREP_debug_write (void *opaque, uint32_t addr, uint32_t val);
@@ -1082,8 +1209,7 @@
void PPC_debug_write (void *opaque, uint32_t addr, uint32_t val);
/* sun4m.c */
-extern QEMUMachine sun4m_machine;
-void pic_set_irq_cpu(int irq, int level, unsigned int cpu);
+extern QEMUMachine ss5_machine, ss10_machine;
/* iommu.c */
void *iommu_init(uint32_t addr);
@@ -1105,31 +1231,37 @@
/* tcx.c */
void tcx_init(DisplayState *ds, uint32_t addr, uint8_t *vram_base,
- unsigned long vram_offset, int vram_size, int width, int height);
+ unsigned long vram_offset, int vram_size, int width, int height,
+ int depth);
/* slavio_intctl.c */
-void *slavio_intctl_init();
+void pic_set_irq_cpu(void *opaque, int irq, int level, unsigned int cpu);
+void *slavio_intctl_init(uint32_t addr, uint32_t addrg,
+ const uint32_t *intbit_to_level,
+ qemu_irq **irq);
void slavio_intctl_set_cpu(void *opaque, unsigned int cpu, CPUState *env);
void slavio_pic_info(void *opaque);
void slavio_irq_info(void *opaque);
-void slavio_pic_set_irq(void *opaque, int irq, int level);
-void slavio_pic_set_irq_cpu(void *opaque, int irq, int level, unsigned int cpu);
/* loader.c */
int get_image_size(const char *filename);
int load_image(const char *filename, uint8_t *addr);
-int load_elf(const char *filename, int64_t virt_to_phys_addend, uint64_t *pentry);
+int load_elf(const char *filename, int64_t virt_to_phys_addend,
+ uint64_t *pentry, uint64_t *lowaddr, uint64_t *highaddr);
int load_aout(const char *filename, uint8_t *addr);
+int load_uboot(const char *filename, target_ulong *ep, int *is_linux);
/* slavio_timer.c */
-void slavio_timer_init(uint32_t addr, int irq, int mode, unsigned int cpu);
+void slavio_timer_init(uint32_t addr, int irq, int mode, unsigned int cpu,
+ void *intctl);
/* slavio_serial.c */
-SerialState *slavio_serial_init(int base, int irq, CharDriverState *chr1, CharDriverState *chr2);
-void slavio_serial_ms_kbd_init(int base, int irq);
+SerialState *slavio_serial_init(int base, qemu_irq irq, CharDriverState *chr1,
+ CharDriverState *chr2);
+void slavio_serial_ms_kbd_init(int base, qemu_irq);
/* slavio_misc.c */
-void *slavio_misc_init(uint32_t base, int irq);
+void *slavio_misc_init(uint32_t base, qemu_irq irq);
void slavio_set_power_fail(void *opaque, int power_failing);
/* esp.c */
@@ -1138,8 +1270,8 @@
void esp_reset(void *opaque);
/* sparc32_dma.c */
-void *sparc32_dma_init(uint32_t daddr, int espirq, int leirq, void *iommu,
- void *intctl);
+void *sparc32_dma_init(uint32_t daddr, qemu_irq espirq, qemu_irq leirq,
+ void *iommu);
void ledma_set_irq(void *opaque, int isr);
void ledma_memory_read(void *opaque, target_phys_addr_t addr,
uint8_t *buf, int len, int do_bswap);
@@ -1223,7 +1355,7 @@
/* cuda.c */
extern ADBBusState adb_bus;
-int cuda_init(SetIRQFunc *set_irq, void *irq_opaque, int irq);
+int cuda_init(qemu_irq irq);
#include "hw/usb.h"
@@ -1271,8 +1403,7 @@
void *lsi_scsi_init(PCIBus *bus, int devfn);
/* integratorcp.c */
-extern QEMUMachine integratorcp926_machine;
-extern QEMUMachine integratorcp1026_machine;
+extern QEMUMachine integratorcp_machine;
/* versatilepb.c */
extern QEMUMachine versatilepb_machine;
@@ -1282,10 +1413,10 @@
extern QEMUMachine realview_machine;
/* spitz.c */
-extern QEMUMachine zaurusakita_machine;
-extern QEMUMachine zaurusspitz_machine;
-extern QEMUMachine zaurusborzoi_machine;
-extern QEMUMachine zaurusterrier_machine;
+extern QEMUMachine akitapda_machine;
+extern QEMUMachine spitzpda_machine;
+extern QEMUMachine borzoipda_machine;
+extern QEMUMachine terrierpda_machine;
/* neo1973.c */
extern QEMUMachine neo1973_machine;
@@ -1298,38 +1429,43 @@
uint32_t ps2_read_data(void *);
void ps2_queue(void *, int b);
void ps2_keyboard_set_translation(void *opaque, int mode);
+void ps2_mouse_fake_event(void *opaque);
/* smc91c111.c */
-void smc91c111_init(NICInfo *, uint32_t, void *, int);
+void smc91c111_init(NICInfo *, uint32_t, qemu_irq);
/* pl110.c */
-void *pl110_init(DisplayState *ds, uint32_t base, void *pic, int irq, int);
+void *pl110_init(DisplayState *ds, uint32_t base, qemu_irq irq, int);
/* pl011.c */
-void pl011_init(uint32_t base, void *pic, int irq, CharDriverState *chr);
+void pl011_init(uint32_t base, qemu_irq irq, CharDriverState *chr);
/* pl050.c */
-void pl050_init(uint32_t base, void *pic, int irq, int is_mouse);
+void pl050_init(uint32_t base, qemu_irq irq, int is_mouse);
/* pl080.c */
-void *pl080_init(uint32_t base, void *pic, int irq, int nchannels);
+void *pl080_init(uint32_t base, qemu_irq irq, int nchannels);
+/* pl181.c */
+void pl181_init(uint32_t base, BlockDriverState *bd,
+ qemu_irq irq0, qemu_irq irq1);
+
/* pl190.c */
-void *pl190_init(uint32_t base, void *parent, int irq, int fiq);
+qemu_irq *pl190_init(uint32_t base, qemu_irq irq, qemu_irq fiq);
/* arm-timer.c */
-void sp804_init(uint32_t base, void *pic, int irq);
-void icp_pit_init(uint32_t base, void *pic, int irq);
+void sp804_init(uint32_t base, qemu_irq irq);
+void icp_pit_init(uint32_t base, qemu_irq *pic, int irq);
/* arm_sysctl.c */
void arm_sysctl_init(uint32_t base, uint32_t sys_id);
/* arm_gic.c */
-void *arm_gic_init(uint32_t base, void *parent, int parent_irq);
+qemu_irq *arm_gic_init(uint32_t base, qemu_irq parent_irq);
/* arm_boot.c */
-void arm_load_kernel(int ram_size, const char *kernel_filename,
+void arm_load_kernel(CPUState *env, int ram_size, const char *kernel_filename,
const char *kernel_cmdline, const char *initrd_filename,
int board_id, target_phys_addr_t loader_start);
@@ -1356,6 +1492,8 @@
int tc58128_init(struct SH7750State *s, char *zone1, char *zone2);
/* NOR flash devices */
+#define MAX_PFLASH 4
+extern BlockDriverState *pflash_table[MAX_PFLASH];
typedef struct pflash_t pflash_t;
pflash_t *pflash_register (target_ulong base, ram_addr_t off,
@@ -1385,31 +1523,33 @@
#include "ecc.h"
+/* ads7846.c */
+struct ads7846_state_s;
+uint32_t ads7846_read(void *opaque);
+void ads7846_write(void *opaque, uint32_t value);
+struct ads7846_state_s *ads7846_init(qemu_irq penirq);
+
/* max111x.c */
struct max111x_s;
uint32_t max111x_read(void *opaque);
void max111x_write(void *opaque, uint32_t value);
-struct max111x_s *max1110_init(void (*cb)(void *opaque), void *opaque);
-struct max111x_s *max1111_init(void (*cb)(void *opaque), void *opaque);
+struct max111x_s *max1110_init(qemu_irq cb);
+struct max111x_s *max1111_init(qemu_irq cb);
void max111x_set_input(struct max111x_s *s, int line, uint8_t value);
-/* ads7846.c */
-struct ads7846_state_s;
-uint32_t ads7846_read(void *opaque);
-void ads7846_write(void *opaque, uint32_t value);
-struct ads7846_state_s *ads7846_init(
- void (*penirq)(void *opaque, int level), void *opaque);
-
/* jbt6k74.c */
uint8_t jbt6k74_txrx(void *opaque, uint8_t value);
uint8_t jbt6k74_btxrx(void *opaque, uint8_t value);
void *jbt6k74_init();
+/* modem.c */
+CharDriverState *modem_init();
+void modem_enable(CharDriverState *chr, int enable);
+
/* PCMCIA/Cardbus */
struct pcmcia_socket_s {
- void (*set_irq)(void *opaque, int irq, int level);
- void *opaque;
+ qemu_irq irq;
int attached;
const char *slot_string;
const char *card_string;
@@ -1428,12 +1568,12 @@
int cis_len;
/* Only valid if attached */
- uint8_t (*attr_read)(void *state, uint16_t address);
- void (*attr_write)(void *state, uint16_t address, uint8_t value);
- uint16_t (*common_read)(void *state, uint16_t address);
- void (*common_write)(void *state, uint16_t address, uint16_t value);
- uint16_t (*io_read)(void *state, uint16_t address);
- void (*io_write)(void *state, uint16_t address, uint16_t value);
+ uint8_t (*attr_read)(void *state, uint32_t address);
+ void (*attr_write)(void *state, uint32_t address, uint8_t value);
+ uint16_t (*common_read)(void *state, uint32_t address);
+ void (*common_write)(void *state, uint32_t address, uint16_t value);
+ uint16_t (*io_read)(void *state, uint32_t address);
+ void (*io_write)(void *state, uint32_t address, uint16_t value);
};
#define CISTPL_DEVICE 0x01 /* 5V Device Information Tuple */
@@ -1456,20 +1596,12 @@
/* dscm1xxxx.c */
struct pcmcia_card_s *dscm1xxxx_init(BlockDriverState *bdrv);
-typedef void (*gpio_handler_t)(int line, int level, void *opaque);
-
-#include "hw/i2c.h"
-
#define unlikely(cond) __builtin_expect(!!(cond), 0)
-#ifdef TARGET_ARM
#include "hw/pxa.h"
#include "hw/s3c.h"
-#endif
-/* modem.c */
-CharDriverState *modem_init();
-void modem_enable(CharDriverState *chr, int enable);
+#include "gdbstub.h"
#endif /* defined(QEMU_TOOL) */
Modified: trunk/src/host/qemu-neo1973/vnc.c
===================================================================
--- trunk/src/host/qemu-neo1973/vnc.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/vnc.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -68,6 +68,13 @@
int depth; /* internal VNC frame buffer byte per pixel */
int has_resize;
int has_hextile;
+ int has_pointer_type_change;
+ int absolute;
+ int last_x;
+ int last_y;
+
+ const char *display;
+
Buffer output;
Buffer input;
kbd_layout_t *kbd_layout;
@@ -85,6 +92,24 @@
uint8_t modifiers_state[256];
};
+static VncState *vnc_state; /* needed for info vnc */
+
+void do_info_vnc(void)
+{
+ if (vnc_state == NULL)
+ term_printf("VNC server disabled\n");
+ else {
+ term_printf("VNC server active on: ");
+ term_print_filename(vnc_state->display);
+ term_printf("\n");
+
+ if (vnc_state->csock == -1)
+ term_printf("No client connected\n");
+ else
+ term_printf("Client connected\n");
+ }
+}
+
/* TODO
1) Get the queue working for IO.
2) there is some weirdness when using the -S option (the screen is grey
@@ -671,6 +696,19 @@
{
}
+static void check_pointer_type_change(VncState *vs, int absolute)
+{
+ if (vs->has_pointer_type_change && vs->absolute != absolute) {
+ vnc_write_u8(vs, 0);
+ vnc_write_u8(vs, 0);
+ vnc_write_u16(vs, 1);
+ vnc_framebuffer_update(vs, absolute, 0,
+ vs->ds->width, vs->ds->height, -257);
+ vnc_flush(vs);
+ }
+ vs->absolute = absolute;
+}
+
static void pointer_event(VncState *vs, int button_mask, int x, int y)
{
int buttons = 0;
@@ -686,21 +724,26 @@
dz = -1;
if (button_mask & 0x10)
dz = 1;
-
- if (kbd_mouse_is_absolute()) {
+
+ if (vs->absolute) {
kbd_mouse_event(x * 0x7FFF / vs->ds->width,
y * 0x7FFF / vs->ds->height,
dz, buttons);
+ } else if (vs->has_pointer_type_change) {
+ x -= 0x7FFF;
+ y -= 0x7FFF;
+
+ kbd_mouse_event(x, y, dz, buttons);
} else {
- static int last_x = -1;
- static int last_y = -1;
+ if (vs->last_x != -1)
+ kbd_mouse_event(x - vs->last_x,
+ y - vs->last_y,
+ dz, buttons);
+ vs->last_x = x;
+ vs->last_y = y;
+ }
- if (last_x != -1)
- kbd_mouse_event(x - last_x, y - last_y, dz, buttons);
-
- last_x = x;
- last_y = y;
- }
+ check_pointer_type_change(vs, kbd_mouse_is_absolute());
}
static void reset_keys(VncState *vs)
@@ -809,6 +852,15 @@
int x_position, int y_position,
int w, int h)
{
+ if (x_position > vs->ds->width)
+ x_position = vs->ds->width;
+ if (y_position > vs->ds->height)
+ y_position = vs->ds->height;
+ if (x_position + w >= vs->ds->width)
+ w = vs->ds->width - x_position;
+ if (y_position + h >= vs->ds->height)
+ h = vs->ds->height - y_position;
+
int i;
vs->need_update = 1;
if (!incremental) {
@@ -829,6 +881,8 @@
vs->has_hextile = 0;
vs->has_resize = 0;
+ vs->has_pointer_type_change = 0;
+ vs->absolute = -1;
vs->ds->dpy_copy = NULL;
for (i = n_encodings - 1; i >= 0; i--) {
@@ -845,10 +899,15 @@
case -223: /* DesktopResize */
vs->has_resize = 1;
break;
+ case -257:
+ vs->has_pointer_type_change = 1;
+ break;
default:
break;
}
}
+
+ check_pointer_type_change(vs, kbd_mouse_is_absolute());
}
static int compute_nbits(unsigned int val)
@@ -1006,6 +1065,8 @@
static int protocol_client_init(VncState *vs, char *data, size_t len)
{
char pad[3] = { 0, 0, 0 };
+ char buf[1024];
+ int size;
vs->width = vs->ds->width;
vs->height = vs->ds->height;
@@ -1050,8 +1111,13 @@
vnc_write(vs, pad, 3); /* padding */
- vnc_write_u32(vs, 4);
- vnc_write(vs, "QEMU", 4);
+ if (qemu_name)
+ size = snprintf(buf, sizeof(buf), "QEMU (%s)", qemu_name);
+ else
+ size = snprintf(buf, sizeof(buf), "QEMU");
+
+ vnc_write_u32(vs, size);
+ vnc_write(vs, buf, size);
vnc_flush(vs);
vnc_read_when(vs, protocol_client_msg, 1);
@@ -1120,10 +1186,14 @@
exit(1);
ds->opaque = vs;
+ vnc_state = vs;
+ vs->display = arg;
vs->lsock = -1;
vs->csock = -1;
vs->depth = 4;
+ vs->last_x = -1;
+ vs->last_y = -1;
vs->ds = ds;
Added: trunk/src/host/qemu-neo1973/x_keymap.c
===================================================================
--- trunk/src/host/qemu-neo1973/x_keymap.c 2007-05-11 08:16:15 UTC (rev 1947)
+++ trunk/src/host/qemu-neo1973/x_keymap.c 2007-05-11 23:44:50 UTC (rev 1948)
@@ -0,0 +1,110 @@
+/*
+ * QEMU SDL display 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.
+ */
+#include "vl.h"
+static const uint8_t x_keycode_to_pc_keycode[115] = {
+ 0xc7, /* 97 Home */
+ 0xc8, /* 98 Up */
+ 0xc9, /* 99 PgUp */
+ 0xcb, /* 100 Left */
+ 0x4c, /* 101 KP-5 */
+ 0xcd, /* 102 Right */
+ 0xcf, /* 103 End */
+ 0xd0, /* 104 Down */
+ 0xd1, /* 105 PgDn */
+ 0xd2, /* 106 Ins */
+ 0xd3, /* 107 Del */
+ 0x9c, /* 108 Enter */
+ 0x9d, /* 109 Ctrl-R */
+ 0x0, /* 110 Pause */
+ 0xb7, /* 111 Print */
+ 0xb5, /* 112 Divide */
+ 0xb8, /* 113 Alt-R */
+ 0xc6, /* 114 Break */
+ 0x0, /* 115 */
+ 0x0, /* 116 */
+ 0x0, /* 117 */
+ 0x0, /* 118 */
+ 0x0, /* 119 */
+ 0x0, /* 120 */
+ 0x0, /* 121 */
+ 0x0, /* 122 */
+ 0x0, /* 123 */
+ 0x0, /* 124 */
+ 0x0, /* 125 */
+ 0x0, /* 126 */
+ 0x0, /* 127 */
+ 0x0, /* 128 */
+ 0x79, /* 129 Henkan */
+ 0x0, /* 130 */
+ 0x7b, /* 131 Muhenkan */
+ 0x0, /* 132 */
+ 0x7d, /* 133 Yen */
+ 0x0, /* 134 */
+ 0x0, /* 135 */
+ 0x47, /* 136 KP_7 */
+ 0x48, /* 137 KP_8 */
+ 0x49, /* 138 KP_9 */
+ 0x4b, /* 139 KP_4 */
+ 0x4c, /* 140 KP_5 */
+ 0x4d, /* 141 KP_6 */
+ 0x4f, /* 142 KP_1 */
+ 0x50, /* 143 KP_2 */
+ 0x51, /* 144 KP_3 */
+ 0x52, /* 145 KP_0 */
+ 0x53, /* 146 KP_. */
+ 0x47, /* 147 KP_HOME */
+ 0x48, /* 148 KP_UP */
+ 0x49, /* 149 KP_PgUp */
+ 0x4b, /* 150 KP_Left */
+ 0x4c, /* 151 KP_ */
+ 0x4d, /* 152 KP_Right */
+ 0x4f, /* 153 KP_End */
+ 0x50, /* 154 KP_Down */
+ 0x51, /* 155 KP_PgDn */
+ 0x52, /* 156 KP_Ins */
+ 0x53, /* 157 KP_Del */
+ 0x0, /* 158 */
+ 0x0, /* 159 */
+ 0x0, /* 160 */
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, /* 170 */
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, /* 180 */
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, /* 190 */
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, /* 200 */
+ 0x0, /* 201 */
+ 0x0, /* 202 */
+ 0x0, /* 203 */
+ 0x0, /* 204 */
+ 0x0, /* 205 */
+ 0x0, /* 206 */
+ 0x0, /* 207 */
+ 0x70, /* 208 Hiragana_Katakana */
+ 0x0, /* 209 */
+ 0x0, /* 210 */
+ 0x73, /* 211 backslash */
+};
+
+uint8_t _translate_keycode(const int key)
+{
+ return x_keycode_to_pc_keycode[key];
+}
More information about the commitlog
mailing list